一:Mybatis基于代理Dao的CRUD操作

1.CRUD的实现步骤:

(1)在持久层接口(IUserDao)添加对应的方法
例如:

/**
* 用户的持久层接口
* @author Mango
*/
public interface IUserDao {

/**
* 查询所有操作
* @return
*/
List<User> findAll();

(2)然后在用户映射配置文件(IUserDao.xml)中配置

<!--    配置查询所有-->
<!-- dao的方法名称,会把结果集封装到User-->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user;
</select>

细节:
resultType 属性:用于指定结果集(返回值)的类型。 parameterType 属性:用于指定传入参数的类型。
sql 语句中使用#{} 字符 :它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。#{} 中内容的写法:由于数据类型是基本类型,所以此处可以随意写。

(1)ognl 表达式:

它是 apache 提供的一种表达式语言,全称是:Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。语法格式就是使用 #{对象.对象}的方式.

#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.而直接写 username。

(3)测试类测试

private InputStream in;
private SqlSession sqlSession;
private IUserDao userDao;

/**
* 用于在测试方法之前执行
* @throws Exception
*/
@Before
public void init() throws Exception{
//1.读取环境里面的总体配置文件(里面参数)
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产一个SqlSession对象
sqlSession = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
userDao = sqlSession.getMapper(IUserDao.class);
}
/**
* 用于在测试方法之后执行
* @throws Exception
*/
@After
public void destory() throws Exception{
//提交事务
sqlSession.commit();

//6.释放资源
sqlSession.close();
in.close();
}


@Test
public void testFindAll() {
//使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}

(2)提交事务:session.commit();

打开 Mysql 数据库发现并没有添加任何记录,原因是什么?这一点和 jdbc 是一样的,我们在实现增删改时一定要去控制事务的提交那么在 mybatis 中可以使用:session.commit();来实现事务提交。

(3)新增用户 id 的返回值

新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。

<!--   保存用户 -->
<insert id="saveUser" parameterType="com.itheima.domain.User">
<!-- 配置插入操作后,获取插入数据的id-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id(); //获取最后插入数据的id
</selectKey>
insert into user(username,address,sex,birthday)values(#{userName},#{address},#{sex},#{birthday});
</insert>

(4)#{} 与${} 的区别

#{} 表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。

${}表示拼接字符串
通过${}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换,$ {}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。

(5)Mybatis 与 与 JDBC 编程的比较

1.数据库链接(Connection)创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:
在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。

2.Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。
解决:
将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。,只改变外部的sql语句

3.向sql语句传参数麻烦,因为sql语句的where 条件不一定,可能多也可能少,占位符需要和参数对应。
解决:
Mybatis自动将 java 对象映射至 sql 语句,通过 statement 中的 parameterType 定义输入参数的类型。

4.对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对
象解析比较方便。

解决:
Mybatis自动将 sql执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的类型。

二:Mybatis 的参数深入(parameterType属性)

parameterType 属性来设定。该属性的取值可以是基本类型,引用类型(例如:String 类型),还可以是实体类类型(POJO 类)同时也可以使用实体类的包装类(QueryVo)

QueryVo

/**
* @author Mango
* 实体类的包装类
*/
public class QueryVo {
private User user;

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}
}

dao层接口映射文件

<!-- 根据用户名称模糊查询,参数变成一个 QueryVo 对象了 -->
<select id="findByVo" resultType="com.itheima.domain.User"
parameterType="com.itheima.domain.QueryVo">
select * from user where username like #{user.username};
</select>

三:Mybatis 的输出结果封装

resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型
需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名。例如:我们的实体类(User)此时必须是全限定类名

同时,当是实体类名称是,还有一个要求,实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。

<!--    配置查询所有-->
<!-- dao的方法名称,会把结果集封装到User-->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user;
</select>

resultMap 结果类型

resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。

type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。

<!--    配置查询结果的列名和实体类的属性名的对应关系-->
<resultMap id="userMap" type="com.itheima.domain.User">
<!-- 主键字段的对应 -->
<id property="id" column="id"></id>
<!-- 主键字段的对应 -->
<result property="userName" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</resultMap>
<!-- 每个dao独立的配置文件-->

<!-- 配置查询所有-->
<!-- dao的方法名称,会把结果集封装到User-->
<select id="findAll" resultMap="userMap">
select * from user;
</select>

四:Mybatis dao实现类开发(了解)

使用 Mybatis 开发 Dao,通常有两个方法,即原始 Dao开发方式和 Mapper 接口代理开发方式。而现在主流的开发方式是接口代理开发方式,这种方式总体上更加简便。

dao接口实现类:

/**
* @author Mango
* dao 的实现类
*/
public class UserDaoImpl implements IUserDao {

private SqlSessionFactory factory;

public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
@Override
public List<User> findAll() {
SqlSession session = factory.openSession();
List<User> users = session.selectList("com.itheima.dao.IUserDao.findAll");
session.close();
return users;
}

}

持久层映射配置

<!-- 配置查询所有操作 -->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
</select>
<!-- 根据 id 查询 -->
<select id="findById" resultType="com.itheima.domain.User" parameterType="int">
select * from user where id = #{uid}
</select>

五:SqlMapConfig.xml 配置文件

(1)properties属性

在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。

在 在 classpath 下定义 jdbc.properties 文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/xxx
jdbc.username=root
jdbc.password=1234

可以保存到本地,通过url进行索引

<!--    配置properties  支持放到外部配置文件 然后下面再引用

resource属性:用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下

url属性:是要求按照url的写法来写地址
URL:Uniform Resource Locator 统一资源定位符,它是可以唯一表示一个资源的位置
它的写法:
http://localhost:8080/mybatisservert/demolServlet
协议 主机 端口 URI
URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的
-->
<properties url="file:///C:/Users/Mango/Desktop/jdbcConfig.properties"></properties>

(2)typeAliases属性

在前面我们讲的 Mybatis 支持的默认别名,我们也可以采用自定义别名方式来开发。
在 SqlMapConfig.xml 中配置:

<!--    使用typeAliases配置别名,它只能配置domain中类的别名-->
<typeAliases>
<!-- typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就别再区分大小写-->
<!-- <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->

<!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
<package name="com.itheima.domain.User"/>
</typeAliases>
<!--    指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<!-- <mapper resource="com/itheima/dao/IUserDao.xml"/>-->

<!-- package标签用于指定dao接口所在的包 当指定后不需要再写mapper以及resource或者class了-->
<package name="com.itheima.dao"/>

</mappers>

注意:此种方法要求 mar pper 接口名称和 r mapper 映射文件名称相同,且放在同一个目录中。