MyBatis
MyBatis
MyBatis 开发步骤:
添加 MyBatis 的坐标
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency>
- 创建 user 数据表
- 创建 User 实体类
编写映射文件 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="userMapper"> <select id="findAll" resultType="com.domain.User"> select * from user </select> </mapper>
编写核心文件 SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration> <!-- 配置数据源环境 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="jie13727507037"/> </dataSource> </environment> </environments> <!-- 加载映射文件 --> <mappers> <mapper resource="com.mapper\UserMapper.xml"/> </mappers> </configuration>
编写测试类
public void test1() throws IOException { // 加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 获得 SQLSession 工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获得 session 会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行操作 参数:namespace+语句id List<User> userList = sqlSession.selectList("userMapper.findAll"); // 打印数据 System.out.println(userList); // 释放资源 sqlSession.close(); }
映射文件概述
MyBatis 的插入操作注意问题
- 插入语句使用 insert 标签
- 在映射文件中使用 parameterType 属性指定要插入的数据类型
- Sql 语句中使用 #{实例属性名} 的方式引用实体中的属性值
- 插入操作使用的 API 是 sqlSession.insert("namespace.id", 实体对象);
- 插入操作涉及数据库数据变化,所以要使用 sqlSession对象显示的提交事务,即 sqlSession.commit()
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="userMapper"> <!-- 查询操作 --> <select id="findAll" resultType="com.domain.User"> select * from user </select> <!-- 插入操作 --> <insert id="save" parameterType="com.domain.User"> insert into user values(#{id}, #{username}, #{password}) </insert> </mapper>
public void test2() throws IOException { // 模拟 user 对象 User user = new User(); user.setUsername("tom"); user.setPassword("abc"); // 加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 获得 SQLSession 工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获得 session 会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行操作 参数:namespace+语句id sqlSession.insert("userMapper.save", user); // mybatis 执行更新操作 需要提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }
MyBatis 修改操作注意问题
- 修改语句使用 update 标签
- 修改操作使用的 API 是 sqlSession.update("namespace.id", 实体对象);
<!-- 修改操作 --> <update id="update" parameterType="com.domain.User"> update user set username=#{username}, password=#{password} where id=#{id} </update>
public void test3() throws IOException { // 模拟 user 对象 User user = new User(); user.setId(7); user.setUsername("lucy"); user.setPassword("123"); // 加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 获得 SQLSession 工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获得 session 会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行操作 参数:namespace+语句id sqlSession.update("userMapper.update", user); // mybatis 执行更新操作 需要提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }
MyBatis 删除操作注意问题
- 删除语句使用 delete 标签
- Sql 语句中使用 #{任意字符串} 方式引用传递的单个参数
- 删除操作使用的 API 是 sqlSession.delete("namespace.id", Object);
<!-- 删除操作 --> <delete id="delete" parameterType="java.lang.Integer"> delete from user where id=#{id} </delete>
public void test4() throws IOException { // 加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 获得 SQLSession 工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获得 session 会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行操作 参数:namespace+语句id sqlSession.delete("userMapper.delete", 7); // mybatis 执行更新操作 需要提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }
MyBatis 核心配置文件常用配置
properties 标签:改标签可以加载外部的 properties 文件
<!-- 加载外部 properties 文件 --> <properties resource="jdbc.properties"/>
typeAliases 标签:设置类型别名
<!-- 定义别名 --> <typeAliases> <typeAlias type="com.domain.User" alias="user"/> </typeAliases>
mappers 标签:加载映射配置
<!-- 加载映射文件 --> <mappers> <mapper resource="com.mapper/UserMapper.xml"/> </mappers>
environments 标签:数据源环境配置标签
<!-- 配置数据源环境 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments>
MyBatis 相应 API
SqlSession 工厂构造器 SqlSessionFactory build(InputStream inputstream)
// 加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 获得 SQLSession 工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession 工厂对象 SqlSessionFactory
- openSession():会默认开启一个事务,但事务不会自动提交,也就是一位置需要手动提交该事务,更新操作数据才会持久化到数据库中
- openSession(boolean autoCommit):参数为是否自动提交,如果设置为 true,那么不需要手动提交事务
// 获得 session 会话对象 SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession 会话对象
执行语句的方法
// 查询单个对象 T selectOne(String statement, Object parameter); // 查询全部 List<E> selectList(String statement, Object parameter); // 插入 int insert(String statement, Object parameter); // 修改 int update(String statement, Object parameter); // 删除 int delete(String statement, Object parameter);
操作事务的方法
void.commit(); // 事务提交 void rollback(); // 事务回滚
MyBatis DAO 层实现
代理开发方式
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Mapper 接口开发需要遵循以下规范
- Mapper.xml 文件中的 namespace 与 mapper 接口的全限定名相同
- Mapper 接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同
- Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同
- Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同
MyBatis 映射文件深入
动态 sql —— if
<select id="findByCondition" resultType="user" parameterType="user"> select * from user <where> <if test="id!=0"> id=#{id} </if> <if test="username!=null"> and username=#{username} </if> <if test="password!=null"> and password=#{password} </if> </where> </select>
动态 sql —— foreach
<select id="findByIds" parameterType="list" resultType="user"> select * from user <where> <foreach collection="list" open="id in(" close=")" item="id" separator=","> #{id} </foreach> </where> </select>
动态 sql —— sql 语句的抽取
<!-- sql 语句的抽取 --> <sql id="selectUser">select * from user</sql> <include refid="selectUser"></include>
MyBatis 核心配置文件深入
typeHandlers 标签
开发步骤
- 定义转换类继承类 BaseTypeHandler<T>
- 覆盖 4 个未实现的方法,其中 setNonNullParameter 为 java 程序设置数据到数据库的回调方法,getNullableResult 为查询时 mysql 的字符串类型转换成 java 的 Type 类型的方法
- 在 MyBatis 核心配置文件中个进行注册
- 测试转换是否正确
plugins 标签
开发步骤
- 导入通用 PageHelper 的坐标
- 在 mybatis 核心配置文件中配置 PageHelper 插件
- 测试分页数据获取
MyBatis 多表操作
一对一
- 第一种配置
```xml
<resultMap id="orderMap" type="order">
<!-- 手动指定字段与实体的映射关系
column: 数据表的字段名称
property: 实体的属性名称
-->
<id column="oid" property="id"/>
<result column="ordertime" property="orderTime"/>
<result column="total" property="total"/>
<result column="uid" property="user.id"/>
<result column="username" property="user.username"/>
<result column="password" property="user.password"/>
<result column="birthday" property="user.birthday"/>
</resultMap>
<select id="findAll" resultMap="orderMap">
select *, o.id oid from orders o, user u where o.id=u.id
</select>
```
- 第二种配置
```xml
<resultMap id="orderMap" type="order">
<!-- 手动指定字段与实体的映射关系
column: 数据表的字段名称
property: 实体的属性名称
-->
<id column="oid" property="id"/>
<result column="ordertime" property="orderTime"/>
<result column="total" property="total"/>
<!--<result column="uid" property="user.id"/>
<result column="username" property="user.username"/>
<result column="password" property="user.password"/>
<result column="birthday" property="user.birthday"/>-->
<!--
property: 当前实体的属性名称
javaType: 当前实体中的属性的类型
-->
<association property="user" javaType="user">
<id column="uid" property="id"/>
<result column="username" property="user.username"/>
<result column="password" property="user.password"/>
<result column="birthday" property="user.birthday"/>
</association>
</resultMap>
<select id="findAll" resultMap="orderMap">
select *, o.id oid from orders o, user u where o.id=u.id
</select>
```
2. 一对多
- ```xml
<resultMap id="userMap" type="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<!-- 配置集合信息
property: 集合名称
ofType: 当前集合中的数据类型
-->
<collection property="orderList" ofType="order">
<id column="oid" property="id"/>
<result column="ordertime" property="orderTime"/>
<result column="total" property="total"/>
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select *, o.id oid from user u, order o where u.id=o.uid
</select>
```
3. 多对多
- ```xml
<resultMap id="userRoleMap" type="user">
<id column="userId" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<collection property="roleList" ofType="role">
<id column="roleId" property="id"/>
<result column="roleName" property="roleName"/>
<result column="roleDesc" property="roleDesc"/>
</collection>
</resultMap>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
select * from user u, sys_user_role ur, sys_role r where u.id=ur.userId and ur.roleId
</select>
```
MyBatis 注解开发
常用注解
- @Insert:实现新增
- @Update:实现更新
- @Delete:实现删除
- @Select:实现查询
- @Result:实现结果集封装
- @Results:可以与 @Result 一起使用,封装多个结果集
- @One:实现一对一结果封装
- @Many:实现一对多结果集封装
简单查询
package com.mapper; import com.domain.User; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; public interface UserMapper { @Insert("insert into user values(#{id}, #{username}, #{password}, #{birthday})") void save(User user); @Delete("delete from user where id=#{id}") void delete(int id); @Update("update user set username=#{username}, password=#{password} where id=#{id}") void update(User user); @Select("select * from user where id=#{id}") User findById(int id); @Select("select * from user") List<User> findAll(); }
<!-- 加载映射关系 --> <mappers> <!-- 指定一个包下的接口 --> <package name="com.mapper"/> </mappers>
复杂查询 —— 一对一
两种方式:
package com.mapper; import com.domain.Order; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import java.util.List; public interface OrderMapper { @Select("select *, o.id oid from orders o, user u where o.id=u.id") @Results({ @Result(column = "oid", property = "id"), @Result(column = "ordertime", property = "orderTime"), @Result(column = "total", property = "total"), @Result(column = "uid", property = "user.id"), @Result(column = "username", property = "user.username"), @Result(column = "password", property = "user.password") }) List<Order> findAll(); }
@Select("select * from orders") @Results({ @Result(column = "id", property = "id"), @Result(column = "ordertime", property = "orderTime"), @Result(column = "total", property = "total"), @Result( javaType = User.class, // 要封装的实体类型 column = "uid", // 根据哪个字段去查询 user 表的数据 property = "user", // 要封装的属性名 // select 属性 代表查询哪个接口的方法获得数据 one = @One(select = "com.mapper.UserMapper.findById") ) }) List<Order> findAll();
复杂查询——一对多
@Select("select * from orders where uid=#{uid}") List<Order> findByUid(int uid);
@Select("select * from user") @Results({ @Result(id = true, column = "id", property = "id"), @Result(column = "username", property = "username"), @Result(column = "password", property = "password"), @Result( javaType = List.class, // 要封装的实体类型 column = "id", // 根据哪个字段去查询 user 表的数据 property = "orderList", // 要封装的属性名 // select 属性 代表查询哪个接口的方法获得数据 many = @Many(select = "com.mapper.OrderMapper.findByUid") ) }) List<User> findUserAndOrderAll();
- 复杂查询 —— 多对多