Mybatis框架---概述(2)
MyBatis
1. 动态SQL语句
1.1. 动态SQL是什么
就是相对与固定SQL。就是通过传入的参数不一样,可以组成不同结构的SQL语句. 这种根据参数的条件修改SQL结构的SQL语句,我们称为动态SQL语句.
1.2. 动态SQL有什么用
1.根据条件组装不同结构的SQL语句,可以提高SQL代码的重用性.
2.满足某些特定需求,如,条件判断查询
1.3. 基于XML的实现
1.3.1. 标签包括
<sql> 用于声明公有的SQL语句块.,在操作标签中使用<include>调用 [不建议用]
不建议的原因,会导致代码难以维护。
<if> 类似java if(){},用于判断
<foreach>:类似java的foreach循环,一般用户批量处理的SQL语句
<trim> :切割标签,主要用于切割关键字的头和尾的字符.新版的Mybatis使用的几率很少.
<set>:使用 set标签就是SQL语言的set关键字,可以在update 的时候set 关键字后面的,逗号可以自动忽略
<where>:使用where标签作为SQL语言的where关键字,好处如果where后面的条件都不成立,忽略where关键字.
<choose> <when> <otherwise> : java的swithc case
1.3.2. 接口文件
package cn.zj.mybatis.mapper; import java.util.List; import org.apache.ibatis.annotations.Param; import cn.zj.mybatis.pojo.User; public interface UserMapper { /** * 根据条件查询结果 * @param user * @return */ List<User> selectByCondition(User user); /** * 根据提交查询总数 * @param user * @return */ Long selectTotalByCondition(User user); /** * 修改用户 * @param user * @return */ int updateUserByNotNull(User user); /** * 批量删除用户 * @param ids * @return */ int deleteByIds(@Param("ids")Integer[] ids); /** * 批量插入 * @param users * @return */ int insertByBatch(@Param("users")List<User> users); }
1.3.3. 映射文件
<?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 配置 mybatis 表的映射 namespache :命名空间(和对应映射的接口的 全限定名一样),通俗讲,当前映射文件的唯一标识 全限定名 : 包名+接口名/类名 --> <mapper namespace="cn.zj.mybatis.mapper.UserMapper"> <!-- sql片段 --> <sql id="condition_sql"> <!-- where 标签 --> <where> <if test="name !=null"> name like concat('%',#{name},'%') </if> <if test="password !=null"> and password = #{password} </if> <if test="age !=null"> and age = #{age} </if> </where> </sql> <!-- 多条件查询 --> <select id="selectByCondition" parameterType="cn.zj.mybatis.pojo.User" resultType="cn.zj.mybatis.pojo.User"> select * from user <!-- 引入sql片段 --> <include refid="condition_sql"/> </select> <!-- 多条件查询总数 --> <select id="selectTotalByCondition" parameterType="cn.zj.mybatis.pojo.User" resultType="long"> select count(*) from user <!-- where 标签 --> <include refid="condition_sql"/> </select> <!-- 修改用户信息(数据不为空的修改) --> <update id="updateUserByNotNull" parameterType="cn.zj.mybatis.pojo.User"> update user <set> <if test="name !=null"> name = #{name}, </if> <if test="password !=null"> password = #{password}, </if> <if test="age !=null"> age = #{age}, </if> </set> where id = #{id} </update> <!-- 批量删除 --> <delete id="deleteByIds" parameterType="integer"> <!-- sql : delete from user where id in (1,2,3,4) --> delete from user where id in <!-- 动态sql语句值 foreach --> <foreach collection="ids" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete> <!-- 批量插入 --> <delete id="insertByBatch" parameterType="list"> <!-- insert into user (name,password,age) values (xx,xx,xx),(xx1,xx1,xx1) --> insert into user (name,password,age) values <foreach collection="users" item="user" separator="," > (#{user.name},#{user.password},#{user.age}) </foreach> </delete> </mapper>
1.3.4. 测试代码
1 package cn.zj.mybatis.test; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.apache.ibatis.session.SqlSession; 7 import org.junit.Test; 8 9 import cn.zj.mybatis.mapper.UserMapper; 10 import cn.zj.mybatis.pojo.User; 11 import cn.zj.mybatis.util.MyBatisUtil; 12 13 public class UserMapperTest { 14 15 @Test 16 public void testSelectByCondition() throws Exception { 17 // 1.创建SqlSession对象 18 SqlSession session = MyBatisUtil.openSession(); 19 20 // 2.创建UserMapper接口的代理对象 21 UserMapper userMapper = session.getMapper(UserMapper.class); 22 23 User user = new User(); 24 // user.setAge(30); 25 user.setName("哥"); 26 List<User> users = userMapper.selectByCondition(user); 27 for (User user2 : users) { 28 System.out.println(user2); 29 } 30 31 Long totalCount = userMapper.selectTotalByCondition(user); 32 System.out.println(totalCount); 33 34 //关闭sesison 35 session.close(); 36 } 37 38 @Test 39 public void testInsert() throws Exception { 40 41 // 1.创建SqlSession对象 42 SqlSession session = MyBatisUtil.openSession(); 43 44 // 2.创建UserMapper接口的代理对象 45 UserMapper userMapper = session.getMapper(UserMapper.class); 46 User user1 = new User(null, "西门吹雪", "xmcx", 25); 47 User user2 = new User(null, "东方不败", "dfbb", 30); 48 49 List<User> users = new ArrayList<>(); 50 51 users.add(user1); 52 users.add(user2); 53 // 3. 执行UserMapper的批量插入方法 54 int row = userMapper.insertByBatch(users); 55 System.out.println(row); 56 57 58 // 4.提交事务(MyBatis是手动提交事务) 59 session.commit(); 60 61 // 5.关闭Session 62 session.close(); 63 } 64 65 66 @Test 67 public void testUpdate() throws Exception { 68 // 1.创建SqlSession对象 69 SqlSession session = MyBatisUtil.openSession(); 70 // 2.创建UserMapper接口的代理对象 71 UserMapper userMapper = session.getMapper(UserMapper.class); 72 73 User user = new User(1, null, "xf", null); 74 // 3.执行修改方法 75 int row = userMapper.updateUserByNotNull(user); 76 System.out.println(row); 77 // 4.提交事务 78 session.commit(); 79 80 // 5.关闭session 81 session.close(); 82 } 83 84 @Test 85 public void testDelete() throws Exception { 86 // 1.创建SqlSession对象 87 SqlSession session = MyBatisUtil.openSession(); 88 // 2.创建UserMapper接口的代理对象 89 UserMapper userMapper = session.getMapper(UserMapper.class); 90 91 Integer[] ids = { 2, 3, 5 }; 92 93 // 3.执行修改方法 94 int row = userMapper.deleteByIds(ids); 95 System.out.println(row); 96 // 4.提交事务 97 session.commit(); 98 99 // 5.关闭session 100 session.close(); 101 } 102 103 }
1.4. 基于注解方式实现
动态sql除了支持xml方式以外,还是支持使用纯注解的方式
主要一下四个注解+对应动态sql语句的类文件
- @SelectProvider 动态查询SQL语句对应注解
- @InsertProvider 动态插入SQL语句对应注解
- @UpdateProvider 动态修改SQL语句对应注解
- @DeleteProvider 动态删除SQL语句对应注解
1.4.1 接口映射文件
1 package cn.zj.mybatis.mapper; 2 3 import java.util.List; 4 5 import org.apache.ibatis.annotations.DeleteProvider; 6 import org.apache.ibatis.annotations.InsertProvider; 7 import org.apache.ibatis.annotations.Param; 8 import org.apache.ibatis.annotations.SelectProvider; 9 import org.apache.ibatis.annotations.UpdateProvider; 10 11 import cn.zj.mybatis.pojo.User; 12 import cn.zj.mybatis.pojo.UserProvider; 13 14 public interface UserMapper { 15 16 17 /* 18 * @SelectProvider(type=UserProvider.class,method="") 19 * @SelectProvider 查询动态sql语句的 注解 20 * type : 编写动态sql语句的类对应的字节码 21 * method : 编写动态sql语句类对应的方法名称 22 * 此方法返回的是一个String字符串,字符串就是拼接sql语句 23 */ 24 @SelectProvider(type=UserProvider.class,method="selectByCondition") 25 List<User> selectByCondition(User user); 26 27 /** 28 * 根据条件查询总数 29 * @param user 30 * @return 31 */ 32 @SelectProvider(type=UserProvider.class,method="selectTotalByCondition") 33 Long selectTotalByCondition(User user); 34 35 36 /** 37 * 修改用户信息,参数不为空的数据才会修改 38 * @param user 39 * @return 40 */ 41 @UpdateProvider(type=UserProvider.class,method="updateByNotNull") 42 int updateByNotNull(User user); 43 44 45 /** 46 * 批量删除 47 * @param ids 48 * @return 49 */ 50 @DeleteProvider(type=UserProvider.class,method="deleteByIds") 51 int deleteByIds(@Param("ids")List<Integer> ids); 52 53 /** 54 * 批量插入 55 * @param users 56 * @return 57 */ 58 @InsertProvider(type=UserProvider.class,method="batchInsert") 59 int batchInsert(@Param("users")List<User> users); 60 }
1.4.2. 动态sql语句文件
1 package cn.zj.mybatis.pojo; 2 3 import java.util.List; 4 5 import org.apache.ibatis.annotations.Param; 6 7 /* 8 * UserMapper接口映射对应的动态SQL语句的的类 9 */ 10 public class UserProvider { 11 12 /** 13 * 返回条件查询对应的动态sql语句 14 * @param user 条件参数 15 * @return sql 16 */ 17 public String selectByCondition(User user) { 18 StringBuilder sb = new StringBuilder(); 19 sb.append("select * from user WHERE 1 = 1 "); 20 //动态拼接SQL语句 21 if(user.getName() !=null) { 22 //使用OGNL表达式获取 对象属性的值 23 sb.append("AND name like concat('%',#{name},'%')"); 24 } 25 if(user.getAge() !=null) { 26 sb.append("AND age = #{age}"); 27 } 28 29 return sb.toString(); 30 } 31 32 public String selectTotalByCondition(User user) { 33 StringBuilder sb = new StringBuilder(); 34 sb.append("select count(1) from user WHERE 1 = 1 "); 35 //动态拼接SQL语句 36 if(user.getName() !=null) { 37 //使用OGNL表达式获取 对象属性的值 38 sb.append("AND name like concat('%',#{name},'%')"); 39 } 40 if(user.getAge() !=null) { 41 sb.append("AND age = #{age}"); 42 } 43 44 return sb.toString(); 45 } 46 47 48 49 public String updateByNotNull(User user) { 50 StringBuilder sb = new StringBuilder(); 51 sb.append("update user set "); 52 53 if(user.getName() !=null) { 54 sb.append("name = #{name},"); 55 } 56 if(user.getPassword() !=null) { 57 sb.append("password = #{password},"); 58 } 59 if(user.getAge() !=null) { 60 sb.append("age = #{age},"); 61 } 62 //删除最后一个多余的逗号 63 sb.deleteCharAt(sb.length()-1); 64 65 sb.append(" where id = #{id}"); 66 67 return sb.toString(); 68 } 69 70 71 public String deleteByIds(@Param("ids")List<Integer> ids) { 72 StringBuilder sb = new StringBuilder(); 73 //delete from user where id in (1,3,5,6); 74 sb.append("delete from user where id in ("); 75 76 for (int i = 0; i < ids.size(); i++) { 77 //使用OGNL 表达式获取集合的每一个数据 #{ids[0]} #{ids[1]} #{ids[2]}... 78 sb.append("#{ids["+i+"]},"); 79 } 80 81 //删除最后一个多余的逗号 82 sb.deleteCharAt(sb.length()-1); 83 84 sb.append(")"); 85 return sb.toString(); 86 } 87 88 public String batchInsert(@Param("users")List<User> users) { 89 StringBuilder sb = new StringBuilder(); 90 // insert into user (name,password,age) values 91 // (xxx,x,xx),(xxx1,x1,xx1),(xxx2,x2,xx2), 92 sb.append("insert into user (name,password,age) values "); 93 94 for (int i = 0; i < users.size(); i++) { 95 sb.append("("); 96 //姓名 97 sb.append("#{users["+i+"].name},"); 98 //密码 99 sb.append("#{users["+i+"].password},"); 100 //年龄 101 sb.append("#{users["+i+"].age}"); 102 sb.append("),"); 103 } 104 //删除最后一个多余的逗号 105 sb.deleteCharAt(sb.length()-1); 106 System.out.println("SQL :"+sb.toString()); 107 return sb.toString(); 108 } 109 }
1.4.3. 测试代码
1 package cn.zj.mybatis.test; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.apache.ibatis.session.SqlSession; 7 import org.junit.Test; 8 9 import cn.zj.mybatis.mapper.UserMapper; 10 import cn.zj.mybatis.pojo.User; 11 import cn.zj.mybatis.util.MyBatisUtil; 12 13 public class UserMapperTest { 14 15 @Test 16 public void testSelectByCondition() throws Exception { 17 // 1.创建SqlSession对象 18 SqlSession session = MyBatisUtil.openSession(); 19 20 // 2.创建UserMapper接口的代理对象 21 UserMapper userMapper = session.getMapper(UserMapper.class); 22 23 User user = new User(); 24 // user.setAge(30); 25 user.setName("哥"); 26 List<User> users = userMapper.selectByCondition(user); 27 for (User user2 : users) { 28 System.out.println(user2); 29 } 30 // 查询总数 31 Long totalCount = userMapper.selectTotalByCondition(conditionUser); 32 System.out.println("totalCount:" + totalCount); 33 // 关闭session 34 session.close(); 35 } 36 37 @Test 38 public void testInsert() throws Exception { 39 40 // 1.创建SqlSession对象 41 SqlSession session = MyBatisUtil.openSession(); 42 43 // 2.创建UserMapper接口的代理对象 44 UserMapper userMapper = session.getMapper(UserMapper.class); 45 User user1 = new User(null, "西门吹雪", "xmcx", 25); 46 User user2 = new User(null, "东方不败", "dfbb", 30); 47 48 List<User> users = new ArrayList<>(); 49 50 users.add(user1); 51 users.add(user2); 52 // 3. 执行UserMapper的批量插入方法 53 int row = userMapper.insertByBatch(users); 54 System.out.println(row); 55 56 57 // 4.提交事务(MyBatis是手动提交事务) 58 session.commit(); 59 60 // 5.关闭Session 61 session.close(); 62 } 63 64 @Test 65 public void testUpdate() throws Exception { 66 // 1.创建SqlSession对象 67 SqlSession session = MyBatisUtil.openSession(); 68 // 2.创建UserMapper接口的代理对象 69 UserMapper userMapper = session.getMapper(UserMapper.class); 70 71 User user = new User(5, null, "xf", null); 72 // 3.执行修改方法 73 int row = userMapper.updateUserByNotNull(user); 74 System.out.println(row); 75 // 4.提交事务 76 session.commit(); 77 78 // 5.关闭session 79 session.close(); 80 } 81 82 @Test 83 public void testDelete() throws Exception { 84 // 1.创建SqlSession对象 85 SqlSession session = MyBatisUtil.openSession(); 86 // 2.创建UserMapper接口的代理对象 87 UserMapper userMapper = session.getMapper(UserMapper.class); 88 89 Integer[] ids = { 2, 3, 5 }; 90 91 // 3.执行修改方法 92 int row = userMapper.deleteByIds(ids); 93 System.out.println(row); 94 // 4.提交事务 95 session.commit(); 96 97 // 5.关闭session 98 session.close(); 99 } 100 }
2. 缓存
在Mybatis里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录.从而提高查询的效率.
缓存作用
提高查询的效率.
2.1. 一级缓存
Mybatis的缓存分为一级缓存\ 二级缓存
一级缓存:所谓的一级缓存就是会话(SqlSesion对象)级别的缓存,就是同一个会话,如果已经查询过的数据会保存一份在内存中,如果会话没有关闭,再次调用同样的方法查询,不会再查询数据库,而是直接从缓存中取出之前查询的数据.
一级缓存默认是打开的,而且是关闭不了的.
如何清空一级缓存.
1.关闭会话.close()
2.进行了操作(增删改),提交了commit();
3.手工清除缓存clearCache()
2.1.1. 测试代码
1 @Test 2 public void testselectAll() { 3 // 1.创建SqlSession对象 4 //SqlSesion对象默认就开启了一级缓存,将已经查询过的数据就缓存到SqlSession的缓存区域 5 //在此会话中如果再次发送同样的请求,那么直接从缓存区域获取数据,不会再发送SQL语句了 6 7 SqlSession session1 = MyBatisUtil.openSession(); 8 //SqlSession session2 = MyBatisUtil.openSession(); 9 // 2.创建UserMapper接口的代理对象 10 UserMapper mapper1 = session1.getMapper(UserMapper.class); 11 12 //UserMapper mapper2 = session2.getMapper(UserMapper.class); 13 //3.执行查询方法 14 List<User> users1 = mapper1.selectAll(); 15 16 //手动清理缓存 17 session1.clearCache(); 18 19 List<User> users2 = mapper1.selectAll(); 20 }
2.2. 二级缓存
一级缓存是SqlSession对象级别,在每一次会话中有效
二级缓存是 SqlSessionFactory级别,在整个应用都有效,可以在多个会话有效
MyBatis本身并没有实现二级缓存
二级缓存需要第三方缓存提供商的支持
Ehcache -第三方缓存(Hibernate框架默认就是支持)
学习地址
http://www.mybatis.org/ehcache-cache/
2.2.1. 下载ehcache
https://github.com/mybatis/ehcache-cache/releases
2.2.2. 配置开启二级缓存
MyBatis开启二级缓存新版本已经默认支持开启二级缓存.可以不改
1 <settings> 2 <!-- 开启二级缓存 --> 3 <setting name="cacheEnabled" value="true"/> 4 </settings>
1.1.1. 导入Ehcachejar包
|
1.1.2. Ehcache依赖 slfj 日志框架,必须要导入slfj的两个jar包
|
1.1.3. 创建 ehcache.xml配置文件
Ehcache有自己的配置文件,在src下面创建ehcache.xml 配置文件
<ehcache> <!-- 缓存的磁盘位置 --> <diskStore path="D:/mybatis_cache"/> <!-- 默认的缓存策略: 如果开发者在某一个需要缓存的文件配置了自定义缓存,就不使用默认的,如果没有配置,就使用默认缓存策略--> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> </ehcache>
|
在映射文件中配置<cache>以及配置对应的缓存策略
<mapper namespace="cn.zj.mybatis.dao.UserMapper"> <!-- 当前表的映射开启支持二级缓存,并设置相关的缓存提供商,以及缓存的相关配置 --> <cache type="org.mybatis.caches.ehcache.EhcacheCache" > <!--最大的空闲时间 --> <property name="timeToIdleSeconds" value="10000"/> <!-- 最大的在线时间 --> <property name="timeToLiveSeconds" value="20000"/> <!-- 内存的大小 b字节 m1 =1024k 1k=1024b --> <property name="maxEntriesLocalHeap" value="2000000"/> <!-- 文件的大小 b字节--> <property name="maxEntriesLocalDisk" value="20000000"/> <!-- 算法 LRU:最少使用优先, "LFU" or "FIFO:先进先出 --> <property name="memoryStoreEvictionPolicy" value="LRU"/> </cache> <select id="selectAll" resultType="User"> select * from user </select> </mapper>
1.1.4. 缓存的命中率因为二级缓存可以缓存到文件(将对象序列化到本地),涉及到对象序列化,那么对应的javaBean对象就必须实现
public class User implements Serializable{ private static final long serialVersionUID = -8366151150155170110L; }
命中率= 从缓存中获取数据的次数/ 查询的总次数 如 : 两次查询 从缓中获取一次 0.5 = 1/2; 0.666666 = 2/3; 命中率越高缓存效果越好
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.0 DEBUG [main] - ==> Preparing: select * from user where id = ? DEBUG [main] - ==> Parameters: 3(Integer) DEBUG [main] - <== Total: 1 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.5 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.6666666666666666 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.75 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8333333333333334 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8571428571428571 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.875 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8888888888888888 DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.9
在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值连接), 等值连接 表与表之间有一个外键关键 但是程序中最终获取的表封装的对象, 对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系 对象之间关系主要是四种 一对一 关系 一个人对应身份证id,一个QQ号对应一个QQ空间 一对多 关系 一个部门对应多个员工 多对一 关系 多个员工对应一个部门 多对多 关系 多个学生对应多个老师,多个学生对应多个课程 什么关系应该从哪个对象作为中心点来看 一对多, 以one方作为中心点 MyBatis框架支持多表查询封装对象之间关系 <collection> 一对多查询 <association>多对一和一对一查询
2.1. 准备多表,表之间有外键关系(员工表和部门表)2. MyBatis的对象关系映射(难点重点)
员工表 CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `dept_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; 部门表 CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
|
2.2. 多对一查询
public class Employee { private Integer id; private String name; //以员工为中心 : 多个员工对应一个部门,多对一关系,many2one //员工与部门的对象关系 private Department dept;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Department getDept() { return dept; }
public void setDept(Department dept) { this.dept = dept; }
@Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", dept=" + dept + "]"; } } |
public class Department { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Department [id=" + id + ", name=" + name + "]"; } } |
Man2oneMapper.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"> <!-- 映射配置 namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称 --> <mapper namespace="cn.zj.mybatis.mapper.Many2OneMapper">
<select id="selectByEmpId" parameterType="Integer" resultMap="emp_map">
select * from employee where id = #{id}
</select>
<resultMap type="cn.zj.mybatis.pojo.Employee" id="emp_map">
<id column="id" property="id"/> <result column="name" property="name"/>
<!-- 需要映射部门对象属性 private Department dept;
解决方案,使用关联查询 <association property="dept" column="dept_id" select=""/> property :需要映射的属性 column :要映射属性对应的外键列 select :对应的查询方案, 对应查询的命名空间+.+功能id --> <association property="dept" column="dept_id" select="cn.zj.mybatis.mapper.Many2OneMapper.findDeptById"/>
</resultMap>
<!-- 根据部门Id查询对应的部门对象 --> <select id="findDeptById" parameterType="Integer" resultType="cn.zj.mybatis.pojo.Department"> select * from department where id = #{dept_id} </select>
</mapper> |
2.3. 一对多查询
以部门为中心查询部门的所有信息(包括员工),一个部门对应多个员工
Pojo对象 |
public class Department { private Integer id; private String name;
//以部门为中心:一个部门对应多个与员工 一对多关系 (one2many) private List<Employee> emps;
public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Employee> getEmps() { return emps; } public void setEmps(List<Employee> emps) { this.emps = emps; } @Override public String toString() { return "Department [id=" + id + ", name=" + name + ", emps=" + emps + "]"; } } |
public class Employee { private Integer id; private String name;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + "]"; } } |
2.3.1. N+1方式
N+1 : N 就是当前需要查询结果对应发送的SQL语句的条数
+1 关联查询数据需要额外多发一条SQL语句才能查询出对应的结果
2.3.1.1. 映射代码
<?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"> <!-- 映射配置 namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称 --> <mapper namespace="cn.zj.mybatis.mapper.One2ManyMapper">
<select id="selectDeptById" parameterType="Integer" resultMap="dept_map">
select * from department where id = #{id}
</select>
<!-- 手动映射 --> <resultMap type="cn.zj.mybatis.pojo.Department" id="dept_map"> <id column="id" property="id"/> <result column="name" property="name"/>
<!-- private List<Employee> emps; 集合属性映射 <collection property="emps" column="id" select=""/> property:需要映射得集合 emps column : 部门的主键 id select : 关联查询,去根据部门id查询出对应的员工 值关联查询功能的 命名空间+.+功能id --> <collection property="emps" column="id" select="cn.zj.mybatis.mapper.One2ManyMapper.selectUsersByDeptId"/>
</resultMap>
<!-- 关联查询的功能 根据部门的id查询所有的员工 --> <select id="selectUsersByDeptId" parameterType="integer" resultType="cn.zj.mybatis.pojo.Employee"> select * from employee where dept_id = #{id} </select> </mapper> |
2.3.1.2. 运行结果
|
2.3.2. 等值连接查询
2.3.2.1. 映射代码
<?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"> <!-- 映射配置 namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称 --> <mapper namespace="cn.zj.mybatis.mapper.One2ManyMapper">
<select id="selectDeptById" parameterType="Integer" resultMap="dept_map">
select e.id e_id ,e.name e_name,d.id d_id,d.name d_name from department d JOIN employee e ON d.id = e.dept_id WHERE d.id = #{id};
</select>
<!-- 手动映射 --> <resultMap type="Department" id="dept_map"> <id column="d_id" property="id"/> <result column="d_name" property="name"/>
<!-- private List<Employee> emps; 集合属性映射 <collection property="emps" column="id" select=""/> property:需要映射得集合 emps column : 部门的主键 id ofType : 需要映射集合的泛型的类型 -->
<collection property="emps" ofType="Employee"> <!-- 集合泛型类型对应的pojo的主键列映射 ,Employee的主键列映射 --> <id column="e_id" property="id"/> <!-- 集合泛型类型对应的pojo的非主键列映射 ,Employee的非主键列映射 --> <result column="e_name" property="name"/> </collection>
</resultMap>
</mapper> |
2.3.2.2. 运行结果
只会发送一条SQL语句
DEBUG [main] - ==> Preparing: select e.id e_id ,e.name e_name,d.id d_id,d.name d_name from department d JOIN employee e ON d.id = e.dept_id WHERE d.id = ?; DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 2 Department [id=1, name=总经办, emps=[Employee [id=1, name=乔峰], Employee [id=3, name=段誉]]] |
3. MyBatis的逆向工程
MyBatis的逆向工程能自动帮开发者生成数据库表对应的 pojo实体文件,自动生成映射文件 自定生成表的各种(CRUD)的sql语句, 但是只能做单表操作,联合查询还得开发者自己动
使用逆向工程得先在Eclipse安装逆向工程的插件 |
3.1. 插件安装步骤
|
|
|
判断是否安装成功
|
3.2. 逆向工程步骤
3.2.1. 新建一个普通java项目,导入mybatis.jar包和数据库驱动包
|
3.2.2. 生成配置文件
|
配置生成文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="context1"> <!-- 注释构建 --> <commentGenerator> <!-- 去掉所有的注释 --> <property name="suppressAllComments" value="true"/> <property name="suppressDate" value="true"/> </commentGenerator>
<!-- 数据库四要素 --> <jdbcConnection connectionURL="jdbc:mysql://localhost:3306/mybatis" driverClass="com.mysql.jdbc.Driver" password="admin" userId="root" /> <!-- 实体类 : pojo targetPackage : 实体类生成后存放的包 targetProject : 存放的目录一般都放在 src下面 --> <javaModelGenerator targetPackage="cn.zj.mybatis.pojo" targetProject="mybatis-generator/src" /> <!-- 映射文件 --> <sqlMapGenerator targetPackage="cn.zj.mybatis.mapper" targetProject="mybatis-generator/src" /> <!-- 操作接口 type 生成映射的形式 ANNOTATEDMAPPER : 纯注解的,没有xml映射 XMLMAPPER : 生成的有xml映射文件 --> <javaClientGenerator targetPackage="cn.zj.mybatis.mapper" targetProject="mybatis-generator/src" type="XMLMAPPER" />
<!-- 要生成对应表的配置 tableName : 数据库表名 //如果下面全部是true,mybatis直接可以使用纯面向对象开发 enableCountByExample : 是否生成查询总数的 Example enableDeleteByExample : 是否生成删除的 Example enableSelectByExample : 是否生成查询集合的 Example enableUpdateByExample : 是否生成修改的 Example --> <table tableName="user" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table> <table tableName="employee" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table> <table tableName="department" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table> </context> </generatorConfiguration> |
3.2.3. 开始逆向工程
选中 generatorConfig.xml 逆向工程配置文件,点击鼠标右键
3.3. 逆向功能的缺点
逆向功能不能逆向多表,只能逆向单表操作,多表之间有外键对应java关联关系没办法映射,需要开发者手动编写对应代码