mybatis-generator-core-1.3.2.jar 一、Mybatis 入门案例 1、开发环境准备(Idea) 导入 MyBatis 框架的 jar 包、 MySQL 驱动包、log4j 的 jar 包
导入 log4j 的配置文件(复制粘贴即可) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j :configuration SYSTEM "log4j.dtd" > <log4j:configuration xmlns:log4j ="http://jakarta.apache.org/log4j/" > // 注意这里,自己使用的工具 <appender name ="STDOUT" class ="org.apache.log4j.ConsoleAppender" > <param name ="Encoding" value ="UTF-8" /> <layout class ="org.apache.log4j.PatternLayout" > <param name ="ConversionPattern" value ="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" /> </layout > </appender > <logger name ="java.sql" > <level value ="debug" /> </logger > <logger name ="org.apache.ibatis" > <level value ="info" /> </logger > <root > <level value ="debug" /> <appender-ref ref ="STDOUT" /> </root > </log4j:configuration >
注意:
1 2 3 4 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j :configuration SYSTEM "log4j.dtd" > <log4j:configuration xmlns:log4j ="http://jakarta.apache.org/log4j/" >
这里的 <log4j:configuration xmlns:log4j=”http://jakarta.apache.org/log4j/"> 在 Idea 中会报错
解决办法:
改为:
1 2 3 <!DOCTYPE log4j :configuration SYSTEM "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd" > <log4j:configuration debug ="true" >
最终版: (Idea)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j :configuration SYSTEM "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd" > <log4j:configuration debug ="true" > <appender name ="STDOUT" class ="org.apache.log4j.ConsoleAppender" > <param name ="Encoding" value ="UTF-8" /> <layout class ="org.apache.log4j.PatternLayout" > <param name ="ConversionPattern" value ="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" /> </layout > </appender > <logger name ="java.sql" > <level value ="debug" /> </logger > <logger name ="org.apache.ibatis" > <level value ="info" /> </logger > <root > <level value ="debug" /> <appender-ref ref ="STDOUT" /> </root > </log4j:configuration >
2、创建测试表 1 2 3 4 5 6 7 8 9 10 11 12 CREATE DATABASE test_mybatis;USE test_mybatis; CREATE TABLE tb_user( uid INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR (50 ), password VARCHAR (50 ), age INT , sex VARCHAR (20 ) );
3、创建 javaBean 1 2 3 4 5 6 7 8 9 10 11 public class User { private Integer uid; private String userName; private String password; private Integer age; private String sex; ....生成构造器,以及get、set、toString方法。
4、Mapper 接口 1 2 3 4 public interface UserMapper { User getUserByUid (String uid) ; }
5、创建 MyBatis 的全局配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/test_mybatis" /> // 根据自己的配置 <property name ="username" value ="root" /> <property name ="password" value ="root" /> // 根据自己的配置 </dataSource > </environment > </environments > <mappers > <mapper resource ="UserMapper.xml" /> </mappers > </configuration >
6、创建 Mybatis 的 sql 映射文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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 ="com.oy.online.mapper.UserMapper" > <select id ="getUserByUid" resultType ="com.oy.online.bean.User" > select uid, username, password, age, sex from tb_user where uid = #{uid} </select > </mapper >
7、测试 1 2 3 4 5 6 7 8 9 10 11 12 public class TestMybatis { @Test public void test () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User userByUid = userMapper.getUserByUid("1" ); System.out.println(userByUid); } }
二、MyBatis 全局配置文件 1、MyBatis 全局配置文件简介 文件结构如下:
2、properties 属性 创建一个资源文件,名为jdbc.properties 的文件,将四个连接字符串的数据在资源文件中通过键值 对(key=value)的方式放置 。 1 2 3 4 jdbc.driver =com.mysql.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/test_mybatis jdbc.username =root jdbc.password =root
1 2 3 4 5 6 <properties resource ="jdbc.properties" > </properties >
在 environment 元素的 dataSource 元素中为其动态设置 1 2 3 4 5 6 7 8 9 10 11 <environments default ="mysql" > <environment id ="mysql" > <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 >
3、settings 属性 1 2 3 4 5 6 7 8 <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="aggressiveLazyLoading" value ="false" /> </settings >
4、typeAliases 别名处理 类型别名是为 Java 类型设置一个短的名字,可以方便我们引用某个类。 (typeAlias) 类很多的情况下,可以批量设置别名这个包下的每一个类创建一个默认的别名,就是简单类名小写 。(package) 1 2 3 4 5 6 7 8 <typeAliases > <package name ="com.oy.online.bean" /> </typeAliases >
MyBatis 已经取好的别名
5、environments 环境配置 每种环境使用一个 evironments 标签进行匹配并指定唯一标识符 可以通过 environments 标签中的 defaul 属性指定一个环境的标识符来快速的切换环境。 1 2 3 4 5 6 7 <environments default ="mysql" > ..... </environments >
environment 指定具体环境
id:指定当前环境的唯一标识
transactionManager type: JDBC | MANAGED | 自定义JDBC : 使用了 JDBC 的提交和回滚设置,依赖于从数据源的到的连接来管理事务范围。(JdbcTransactionFactory) MANAGED: 不提交或回滚一个连接、让容器管理事务的整个生命周期(比如 JEE 应用服务器的上下文。ManagedTransactionFactory ) 自定义: 实现 TransationFactory 接口,type = 全类名/别名 5、dataSource
type: UNPOOLED | POOLED | JNDI | 自定义 UNPOOLED: 不使用连接池,UnpooledDataSourceFactory POOLED: 使用连接池, PooledDataSourceFactory JNDI: 在 EJB 或应用服务器这类容器中查找执行的数据源 自定义:实现 DataSourceFactory 接口 ,定义数据源的获取方式 提醒: 实际开发中我们使用 Spring 管理数据源,并进行事务控制的配置来覆盖上述的配置。
6、mappers 映射器 mapper 逐个注册 SQL 映射文件resource : 引入类路径下的文件 url : 引入网络路径或者是磁盘路径下的文件 class : 引入 Mapper 接口。有 SQL 映射文件,要求 Mapper 接口与 SQL 映射文件同名同位置,没有 SQL 映射文件,使用注解在接口的方法上写 SQL 语句。 1 2 3 4 5 <mappers > <mapper resource ="EmployeeMapper.xml" /> <mapper class ="com.OY.mybatis.dao.EmployeeMapper" /> <package name ="com.OY.mybatis.dao" /> </mappers >
使用批量注册,这种方式要求 SQL 映射文件名必须和接口名相同并且在同一目录下 <package> 1 2 3 <mappers > <package name ="com.oy.online.Mapper" /> </mappers >
三、Mybatis 映射文件(CRUD) 1 2 3 4 // namespace: 根据自己的接口来确定 <mapper namespace="com.oy.online.Mapper.UserMapper"> .... </mapper>
SQL 映射文件有很少的几个顶级元素cache – 给定命名空间的缓存配置。 cache-ref – 其他命名空间缓存配置的引用。 resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。 sql – 可被其他语句引用的可重用语句块。 insert – 映射插入语句 update – 映射更新语句 delete – 映射删除语句 select – 映射查询语 1、select Mapper 接口方法
1 2 Emp getEmpByEid (String eid) ;
Mapper 映射文件
1 2 3 <select id ="getEmpByEid" resultType ="com.oy.online.bean.Emp" > select eid, ename, age, sex, did from emp where eid = #{eid} </select >
2、insert Mapper 接口方法
Mapper 映射文件
1 2 3 <insert id ="addEmp" > insert into emp values(null, #{ename}, #{age}, #{sex}) </insert >
3、update Mapper 接口方法
1 2 void updateEmp (Emp emp) ;
Mapper 映射文件
1 2 3 4 <update id ="updateEmp" > update emp set ename = #{ename}, age = #{age}, sex =#{sex} where eid = #{eid} </update >
4、delete Mapper 接口方法
1 2 3 <delete id="deleteEmp" > delete from emp where eid = #{eid} </delete>
Mapper 映射文件
1 2 // 删除员工信息 Boolean deleteEmp(String eid);
四、Mybatis 映射文件(参数传递) 1、主键生成方式、获取主键值 主键生成方式
支持主键自增,例如 MySQL 数据库 不支持主键自增,例如 Oracle 数据库 获取主键值
若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置useGeneratedKeys=”true” ,然后再把 keyProperty 设置到目标属性上。 Mapper 接口方法
1 2 void insertEmp (Emp emp) ;
Mapper 映射文件
1 2 3 4 5 6 7 <insert id ="insertEmp" useGeneratedKeys ="true" keyProperty ="eid" > insert into emp values(null, '${ename}', ${age}, '${sex}') </insert >
测试:
1 2 3 4 5 6 7 8 9 10 @Test public void tes1 () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true ); ParaMpper mapper = sqlSession.getMapper(ParaMpper.class); Emp emp = new Emp (null , "小沫沫" , 12 , "女" ); mapper.insertEmp(emp); System.out.println(emp.getEid()); }
2、 参数的传递 mybatis 获取参数值的两种方式:
${}: insert into emp values(null, admit, 23, 男) Statement: 必须使用字符串拼接的方式操作 SQL,一定要注意单引号问题
#{}:insert into emp values(null, ?,?,?) PrepardStratement: 可以使通配符操作 SQL,因为在为 String 赋值时
使用建议:建议使用#{},在特殊情况下,需要使用${},例如模糊查询和分页查询
参数传递的方式:
当传递参数为单个 String 或基本数据类型和其他包装类 #{} :可以以任意的名字获取参数值 ${} : 只能以${value} 或 ${_parameter} 获取 当传输的参数为 JavaBean 时 #{} 和 ${} 都可以通过属性名直接获取属性值,但是要**注意${}的单引号问题。** 1 insert into emp values (null , '${ename}' , ${age}, '${sex}' )
当传递多个参数时,mybatis 会默认将这些参数放在 map 集合中 两种方式:键为 0,1,2,3…N-1, 以参数为值 键为 param1, param2,param3….paramN, 以参数为值 #{}:#{0},#{1};#{param1}、#{param2} ${}: ${param1}、${param2}, 但是要注意${}的单引号问题 1 2 3 4 5 <select id ="getEmpByEidAndEname" resultType ="Emp" > select eid, ename, age, sex from emp where eid = '${param1}' and ename = '${param2}' </select >
命名参数 为参数使用@Param 起一个名字,Mybatis 就会将这些参数封进 map 中, key 就是我们自己指的名字 Mapper 接口
1 Emp getEmpByEidAndEnameByParam (@Param("eid") String eid, @Param("ename") String ename) ;
Mapper 映射文件
1 2 3 4 <select id ="getEmpByEidAndEnameByParam" resultType ="Emp" > select eid, ename, age, sex from emp where eid = #{eid} and ename = #{ename} </select >
Map 我们也可以封装多个参数为 Map,直接传递 Mapper 映射文件
1 2 3 4 <select id ="getEmpByMap" resultType ="Emp" > select eid, ename, age, sex from emp where eid = ${eid} and ename = '${ename}' </select >
_测试_:
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void test4 () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true ); ParaMpper mapper = sqlSession.getMapper(ParaMpper.class); HashMap<String, Object> map = new HashMap <>(); map.put("eid" , "3" ); map.put("ename" , "小明" ); Emp empByMap = mapper.getEmpByMap(map); System.out.println(empByMap); }
Collection/Array 会被 MyBatis 封装成一个 map 传入, Collection 对应的 key 是 collection,Array 对应的 key 是 array. 如果确定是 List 集合, key 还可以是 list. 3、参数处理 参数位置支持的属性 javaType、 jdbcType、 mode、 numericScale、 resultMap、 typeHandler、 jdbcTypeName、expression
实际上通常被设置的是:可能为空的列名指定 jdbcType ,例如: insert into orcl_employee(id,last_name,email,gender) values(employee_seq.nextval,#{lastName,jdbcType=NULL },#{email},#{gen der})
4、参数的获取方式 #{key}: 获取参数的值,预编译到 SQL 中。安全。 ${key}: 获取参数的值,拼接到 SQL 中。有 SQL 注入问题。 5、select 查询的几种情况 查询单行数据返回单个对象 1 Emp getEmpByEid (String eid) ;
查询数据表中的数量 查询多行数据返回对象的集合 1 public List<Employee> getAllEmps () ;
查询单行数据返回 Map 集合 1 Map<String, Object> getEmpMapByEid (String eid) ;
查询多行数据返回 Map 集合 1 2 @MapKey("eid") Map<String, Object> getAllEmpMap () ;
6、resultMap 自定义映射 自定义 resultMap, 实现高级结果集映射。 id:用于完成主键值的映射。 result:用于完成普通列的映射。 association: 一个复杂的类型关联;许多的结果将包装成这种类型 collection: 复杂的类型集 1 2 3 4 5 <resultMap > :自定义映射,处理复杂的表关系<id column ="eid" property ="eid" /> <id > :设置主键的映射关系,column设置字段名,property设置属性名<result column ="ename" property ="ename" /> <result > :设置非主键的映射关系,column设置字段名,property设置属性名
① id&result
代码示例:
1 2 3 4 5 6 7 8 9 <select id ="getEmployeeById" resultMap ="myEmp" > select id, last_name,email, gender from tbl_employee where id =#{id} </select > <resultMap type ="com.oy.mybatis.beans.Employee" id ="myEmp" > <id column ="id" property ="id" /> <result column ="last_name" property ="lastName" /> <result column ="email" property ="email" /> <result column ="gender" property ="gender" /> </resultMap >
② association (多对一) POJO 中的属性可能会是一个对象,我们可以使用联合查询,并以级联属性的方式封装对象.使用 association 标签定义对象的封装规则 。 1 2 3 4 5 public class Dept { private Integer did; private String dname; ...省略set、get方法 }
1 2 3 4 5 6 7 8 public class Emp { private Integer eid; private String ename; private Integer age; private String sex; private Dept dept; ...省略set、get方法 }
使用级联的方式 1 2 3 4 5 6 7 8 9 10 11 12 13 <resultMap id ="empMap" type ="Emp" > <id column ="eid" property ="eid" /> <result column ="ename" property ="ename" /> <result column ="age" property ="age" /> <result column ="sex" property ="sex" /> <result column ="did" property ="dept.did" /> <result column ="dname" property ="dept.dname" /> </resultMap > <select id ="getAllEmp" resultMap ="empMap" > select e.eid, e.ename, e.age, e.sex, e.did, d.dname from emp e left join dept d on e.did = d.did </select >
Association 1 2 3 4 5 6 7 8 9 10 11 12 13 <resultMap id ="empMap" type ="Emp" > <id column ="eid" property ="eid" /> <result column ="ename" property ="ename" /> <result column ="age" property ="age" /> <result column ="sex" property ="sex" /> <association property ="dept" javaType ="Dept" > //javaType:"com.oy.online.bean.Dept" <id column ="did" property ="did" /> <result column ="dname" property ="dname" /> </association > </resultMap > <select id ="getAllEmp" resultMap ="empMap" > select e.eid, e.ename, e.age, e.sex, e.did, d.dname from emp e left join dept d on e.did = d.did </select >
③ association 分布查询 在世界开发中,对于每个实体类对都应该由具体的增删改查的方法,也就是 DAO 层,因此对于查询员工信息并将对应的部门信息也查询出来的需求,就可以通过分布的方式完成查询。
先通过员工的 id 查询员工的信息 在通过查询出来的员工信息的外键(部门 id) 查询对应的部门信息。 1 2 3 4 5 6 <mapper namespace ="com.oy.online.Mapper.DeptMapper" > <select id ="getDeptByDid" resultType ="Dept" > select did, dname from dept where did = #{did} </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <resultMap id ="empMapStep" type ="Emp" > <id column ="eid" property ="eid" /> <result column ="ename" property ="ename" /> <result column ="age" property ="age" /> <result column ="sex" property ="sex" /> <association property ="dept" select ="com.oy.online.Mapper.DeptMapper.getDeptByDid" column ="did" /> </resultMap > <select id ="getEmpStep" resultMap ="empMapStep" > select eid, ename, age, sex, did from emp where eid = #{eid} </select >
测试:
1 2 3 4 5 6 7 8 9 @Test public void test2 () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpDeptMapper mapper = sqlSession.getMapper(EmpDeptMapper.class); Emp empStep = mapper.getEmpStep("1" ); System.out.println(empStep); }
④ association 分步查询使用延迟加载 在分布查询的基础上,可以使用延迟加载来提升查询的效率,只需要在全局的 Settings 中进行如下配置:
1 2 3 4 <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="aggressiveLazyLoading" value ="false" />
⑤ collection (多对一或多对多) POJO 中的属性可能会是一个集合对象,我们可以使用联合查询,并以级联属性的方式封装对象.使用 collection 标签定义对象的封装规则 。 1 2 3 4 5 6 public class Dept { private Integer did; private String dname; private List<Emp> emps; ...省略set、get方法 }
Collection 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <resultMap id ="deptMap" type ="Dept" > <id column ="did" property ="did" /> <result column ="dname" property ="dname" /> <collection property ="emps" ofType ="Emp" > <id column ="eid" property ="eid" /> <result column ="ename" property ="ename" /> <result column ="age" property ="age" /> <result column ="sex" property ="sex" /> </collection > </resultMap > <select id ="getDeptEmpsByDid" resultMap ="deptMap" > select d.did, d.dname, e.eid, e.ename, e.age, e.sex from dept d left join emp e on d.did = e.did where d.did = #{did} </select >
⑥ collection 分步查询 实际的开发中,对于每个实体类都应该有具体的增删改查方法,也就是 DAO 层, 因此对于查询部门信息并且将对应的所有的员工信息也查询出来的需求,就可以通过分步的方式完成查询。
先通过部门的 id 查询部门信息 再通过部门 id 作为员工的外键查询对应的部门信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <select id ="getEmpListByDid" resultType ="Emp" > select eid, ename, age, sex from emp where did= #{did} </select > <resultMap id ="deprStep" type ="Dept" > <id column ="did" property ="did" /> <result column ="dname" property ="dname" /> <collection property ="emps" select ="com.oy.online.Mapper.EmpDeptMapper.getEmpListByDid" column ="did" > </collection > </resultMap > <select id ="getOnlyDeptByDid" resultMap ="deprStep" > select did, dname from dept where did = #{did} </select >
测试:
1 2 3 4 5 6 7 8 9 10 11 @Test public void test4 () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpDeptMapper mapper = sqlSession.getMapper(EmpDeptMapper.class); Dept onlyDeptByDid = mapper.getOnlyDeptByDid("1" ); System.out.println(onlyDeptByDid); System.out.println("=============================" ); System.out.println(onlyDeptByDid.getDname()); }
⑦ collection 分步查询使用延迟加载 1 2 3 4 <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="aggressiveLazyLoading" value ="false" />
⑧ 扩展: 分步查询多列值的传递 如果分步查询时,需要传递给调用的查询中多个参数,则需要将多个参数封装成 Map 来进行传递,语法如下: {k1=v1, k2=v2….} 在所调用的查询方,取值时就要参考 Map 的取值方式,需要严格的按照封装 map 时所用的 key 来取值. <collection property=”emps” select=”com.oy.online.Mapper.EmpDeptMapper.getEmpListByDid” column=”**{did=did}**”</collection>
⑨ 扩展: association 或 collection 的 fetchType 属性 在<association> 和<collection>标签中都可以设置 fetchType,指定本次查询是否要使用延迟加载。默认为 fetchType=”lazy” ,如果本次的查询不想使用延迟加载,则可设置为 fetchType=”eager” . fetchType 可以灵活的设置查询是否需要使用延迟加载,而不需要因为某个查询不想使用延迟加载将全局的延迟加载设置关闭. <collection property=”emps” select=”com.oy.online.Mapper.EmpDeptMapper.getEmpListByDid” column=”did” **fetchType=”eager”** </collection>
五、Mybatis 动态 SQL 1、Mybatis 动态 SQL 简介 动态的 SQL 是 Mybatis 强大的特征之一。极大的简化我们拼装 SQL 的操作 动态 SQL 元素和使用 JSTL 或其类似基于 XML 的文本处理器相似 Mybatis 采用功能强大的基于 OGNL 的表达式来简化 if choose(when , otherwise) trim(where, set) foreach OGNL( Object Graph Navigation Language )对象图导航语言,这是一种强大的 表达式语言,通过它可以非常方便的来作对象属性。 类似于我们的 EL, SpEL 等。 描述 属性 访问对象属性: person.name 调用方法: person.getName() 调用静态属性/方法: @java.lang.Math@PI @java.util.UUID@randomUUID() 调用构造方法: new com.oy.bean.Person(‘admin’).name 运算符: +,-*,/,% 逻辑运算符: in,not in,>,>=,<,<=,==,!=
注意:xml 中的特殊符号如:“>”,“<”等这些都需要使用转义字符 。
2、if where if 用于简单的判断 Where 用于解决 SQL 语句中的 where 关键字以及条件中第一个 and 或者 or 的问题。(去掉多余的 and) Mapper 接口
1 2 List<Emp> getEmpListByMultiter (Emp emp) ;
Mapper 映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <select id ="getEmpListByMultiter" resultType ="Emp" > select eid, ename, age, sex from emp <where > <if test ="eid != null" > and eid = #{eid} </if > <if test ="ename != null and ename != ''" > and ename = #{ename} </if > <if test ="age != null" > and age = #{age} </if > <if test ="sex == 1 or sex == 2" > and sex = #{sex} </if > </where > </select >
3、trim Trim 可以在条件判断完的 SQL 语句前后添加 或者去掉指定的字符 prefix: 添加前缀(在操作的 SQL 语句前加入某些内容) prefixOverrides: 去掉前缀(把操作的 SQL 语句前的某些内容去掉) suffix: 添加后缀(在操作的 SQL 语句后加入某些内容) suffixOverrides: 去掉后缀 (把操作的 SQL 语句后的某些内容去掉) Mapper 映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <select id ="getEmpListByMultiter" resultType ="Emp" > select eid, ename, age, sex from emp <trim prefix ="where" suffixOverrides ="and|or" > <if test ="eid != null" > eid = #{eid} and </if > <if test ="ename != null and ename != ''" > ename = #{ename} and </if > <if test ="age !=null" > age = #{age} and </if > <if test ="sex == 1 or sex == 0" > sex = #{sex} </if > </trim > </select >
Mapper 接口
1 2 List<Emp> getEmpListByMultiter (Emp emp) ;
4、set set 主要用于解决修改操作中 SQL 语句中可能多出的逗号的问题 Mapper 映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <update id ="updateEmpByConditionSet" > update emp <set > <if test ="ename != null and ename != ''" > ename = #{ename}, </if > <if test ="age != null" > age = #{age}, </if > <if test ="sex == 1 or sex == 2" > sex = #{sex} </if > </set > where eid = #{eid} </update >
Mapper 接口
1 2 void updateEmpByConditionSet (Emp emp) ;
5、Choose(when、otherwise) choose 主要是用于分支判断,类似于 java 中的 switch case, 只会满足所有分支中的一个。
Mapper 映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <select id ="getEmpListByChoose" resultType ="Emp" > select eid, ename, age, sex from emp where <choose > <when test ="eid != null" > eid = #{eid} </when > <when test ="ename != null and ename = ''" > ename = #{ename} </when > <when test ="age != null" > age = #{age} </when > <otherwise > sex = #{sex} </otherwise > </choose > </select >
Mapper 接口
1 2 List<Emp> getEmpListByChoose (Emp emp) ;
6、foreach foreach 主要用于循环迭代collection: 指定要遍历的集合或数组 item: 设置别名 close: 设置循环体开始内容 open: 设置循环体开始内容 separator: 设置每一次循环之间的分隔符 index: 若遍历的是 list, index 代表下标: 若遍历的是 map, index 代表键 ① 批量删除 Mapper 接口
1 2 void deleteMoreByList (@Param("eids") List<Integer> eids) ;
Mapper 映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <delete id ="deleteMoreByList" > delete from emp where <foreach collection ="eids" item ="eid" separator ="or" open ="(" close =")" > eid = #{eid} </foreach > </delete > <delete id ="deleteMoreByList" > delete from emp where eid in <foreach collection ="eids" item ="eid" separator ="," open ="(" close =")" > #{eid} </foreach > </delete >
② 批量查询 Mapper 接口
1 List<Emp> SelectMoreByList (@Param("eids") List<Emp> eids) ;
Mapper 映射
1 2 3 4 5 6 7 8 9 10 11 12 <select id ="SelectMoreByList" resultType ="Emp" > select eid , ename, age, sex from emp where <foreach collection ="eids" item ="eid" separator ="or" > eid = #{eid} </foreach > </select > <select id ="SelectMoreByList1" resultType ="Emp" > select eid , ename, age, sex from emp where eid in <foreach collection ="eids" item ="eid" separator ="," open ="(" close =")" > #{eid} </foreach > </select >
③ 批量添加 Mapper 接口
1 void insertMoreByArray (@Param("emps") Emp[] emps) ;
Mapper 映射
1 2 3 4 5 6 <insert id ="insertMoreByArray" > insert into emp values <foreach collection ="emps" item ="emp" separator ="," > (null, #{emp.ename}, #{emp.age}, #{emp.sex},1) </foreach > </insert >
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void test8 () throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = new Emp (null , "小小" ,12 ,"女" ); Emp emp1 = new Emp (null , "小名" ,14 ,"女" ); Emp emp2 = new Emp (null , "小正" ,17 ,"男" ); Emp emp3 = new Emp (null , "小莫" ,12 ,"男" ); Emp[] emps = {emp, emp1, emp2, emp3, emp3}; mapper.insertMoreByArray(emps); }
③ 批量修改 注意: 执行之前需要在 jdbc.properties 配置文件中的 url 最后配置 “**?allowMultiQueries=true**”
jdbc.url=jdbc:mysql://localhost:3306/test_mybatis**?allowMultiQueries=true**
Mapper 接口
1 void updateMoreByArray (@Param("emps") List<Emp> emps) ;
Mapper 映射
1 2 3 4 5 <update id ="updateMoreByArray" > <foreach collection ="emps" item ="emp" > update emp set ename = #{emp.ename}, age = #{emp.age},sex = #{emp.sex} where eid = #{emp.eid}; </foreach > </update >
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public void test9 () throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = new Emp (14 , "小小" ,12 ,"女" ); Emp emp1 = new Emp (15 , "小明" ,14 ,"男" ); Emp emp2 = new Emp (16 , "小正" ,17 ,"男" ); Emp emp3 = new Emp (17 , "小莫" ,12 ,"男" ); List list = new ArrayList (); list.add(emp); list.add(emp1); list.add(emp2); list.add(emp3); mapper.updateMoreByArray(list); }
7、sql sql 标签是用于抽取可重复的 sql 片段,将相同的,使用频繁的 SQL 片段抽取出来,单独定义,方便多次引用 抽取 SQL 1 2 3 <sql id ="selectSQL" > select eid, ename, age, sex from emp </sql >
引用 SQL: 1 <include refid ="selectSQL" > </include >
六、Mybatis 缓存机制 1、缓存机制 Mybatis 包含一个非常强大的查询的缓存特征,它可以非常方便地搭配配置和定制。缓存可以极大的提升查询效率 Mybatis 系统中的默认定义了两极缓存。 默认情况下,只有一级缓存(Sqlsession 级别的缓存,也称为本地缓存)开启。 二级缓存需要手动开启配置,它是基于 namespace 级别的缓存(映射)。 为了提高扩展性。Mybatis 定义了缓存接口 Cache.我们可以通过实现 Cache 接口来自定义二级缓存。 2、一级缓存的使用 Mapper 接口
1 2 Emp getEmpByEid (String eid) ;
Mapper 映射
1 2 3 4 5 6 7 8 <sql id ="selectSQL" > select eid, ename, age, sex from emp </sql > <select id ="getEmpByEid" resultType ="Emp" > <include refid ="selectSQL" > </include > where eid = #{eid} </select >
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public SqlSessionFactory getSqlSessionFactory () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); return sqlSessionFactory; } @Test public void test1 () throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp empByEid = mapper.getEmpByEid("14" ); System.out.println(empByEid); System.out.println("=================================" ); Emp empByEid1 = mapper.getEmpByEid("14" ); System.out.println(empByEid1); }
说明 :clearCache() 来清空本地缓存
3、一级缓存失效的几种情况 不同的 SqlSession 对应不同的一级缓存 同一个 SqlSession 但是查询条件不同 同一个 SqlSession 两次查询期间执行了任意一次增删改操作 同一个 SqlSession 两次查询期间手动清空了缓存 4、二级缓存的使用 二级缓存(second level cache),全局作用域缓存
二级缓存默认不开启,需要手动配置
Mybatis 提供二级缓存的接口以及实现,缓存实现要求 POJO 实现 Serializable 接口
二级缓存在 SqlSession 关闭或提交之后才会生效
二级缓存使用步骤:
全局配置文件中开启二级缓存<setting name=”cacheEnabled” value=”true”/> 需要使用二级缓存的映射文件处使用 cache 配置缓存<cache /> 注意:POJO 需要实现 Serializable 接口 代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public SqlSessionFactory getSqlSessionFactory () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); return sqlSessionFactory; } @Test public void test2 () throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp empByEid = mapper.getEmpByEid("14" ); System.out.println(empByEid); sqlSession.commit(); System.out.println("===============================" ); Emp empByEid1 = mapper.getEmpByEid("14" ); System.out.println(empByEid1); }
二级缓存相关的属性 属性 描述 eviction=“FIFO” 缓存回收策略: LRU – 最近最少使用的:移除最长时间不被使用的对象。 FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。 WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认的是 LRU flushInterval 刷新间隔,单位毫秒 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新 size 引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出 readOnly 只读, true/false true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。 false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
5、缓存的相关属性设置 全局 setting 的 cacheEnable:
配置二级缓存的开关,一级缓存一直打开的。
select 标签的 userCache 属性: 配置这个 select 是否使用二级缓存。一级缓存一直使用的
sql 标签的 flushCache 属性:
增删改默认 flushCache =true. sql 执行以后,会同时清空一级和二级缓存。
查询默认 flushCache = false。
sqlSession.clearCache(): 只是用来清除一级缓存。
6、整合第三方缓存 为了提高扩展性。myBatis 定义了 缓存接口 Cache。我们可以通过实现 Cache 接口来自定义二级缓存
整合 E 和 Cache 缓存步骤:
① 导入 echcache 包,以及整合包,日志包
② 编写 ehcache,xml 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0" encoding="UTF-8" ?> <ehcache xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation ="../config/ehcache.xsd" > <diskStore path ="D:\atguigu\ehcache" /> <defaultCache maxElementsInMemory ="1000" maxElementsOnDisk ="10000000" eternal ="false" overflowToDisk ="true" timeToIdleSeconds ="120" timeToLiveSeconds ="120" diskExpiryThreadIntervalSeconds ="120" memoryStoreEvictionPolicy ="LRU" > </defaultCache > </ehcache >
注意 :IDEA 中新建 ehcache.xml 文件报错
1 <ehcache xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation ="../config/ehcache.xsd" >
打开 settings - languages&frameworks - schemas and dtds ,添加地址 http://ehcache.org/ehcache.xsd 将 “ ../config/ehcache.xsd ” 改成 “ http://ehcache.org/ehcache.xsd ” ③ 配置 cache 标签
1 <cache type ="org.mybatis.caches.ehcache.EhcacheCache" > </cache >
④ 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test public void test3 () throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp empByEid = mapper.getEmpByEid("14" ); System.out.println(empByEid); sqlSession.commit(); System.out.println("====================================" ); EmpMapper mapper1 = sqlSession.getMapper(EmpMapper.class); Emp empByEid1 = mapper.getEmpByEid("6" ); System.out.println(empByEid1); sqlSession.commit(); System.out.println("====================================" ); EmpMapper mapper2 = sqlSession.getMapper(EmpMapper.class); Emp empByEid2 = mapper.getEmpByEid("7" ); System.out.println(empByEid2); }
七、MyBatis 逆向工程 1、逆向工程的配置 导入逆向工程的 jar 包
mybatis-generator-core-1.3.2.jar
编写 MBG 的配置文件(重要几处配置),可参考官方手册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <?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 ="DB2Tables" targetRuntime ="MyBatis3" > <jdbcConnection driverClass ="com.mysql.jdbc.Driver" connectionURL ="jdbc:mysql://localhost:3306/test_mybatis" userId ="root" password ="root" > </jdbcConnection > <javaTypeResolver > <property name ="forceBigDecimals" value ="false" /> </javaTypeResolver > <javaModelGenerator targetPackage ="com.oy.online.bean" targetProject =".\src" > <property name ="enableSubPackages" value ="true" /> <property name ="trimStrings" value ="true" /> </javaModelGenerator > <sqlMapGenerator targetPackage ="com.oy.online.Mapper" targetProject =".\config" > <property name ="enableSubPackages" value ="true" /> </sqlMapGenerator > <javaClientGenerator type ="XMLMAPPER" targetPackage ="com.oy.online.Mapper" targetProject =".\src" > <property name ="enableSubPackages" value ="true" /> </javaClientGenerator > <table tableName ="emp" domainObjectName ="Emp" > </table > <table tableName ="dept" domainObjectName ="Dept" > </table > </context > </generatorConfiguration >
运行代码生成器生成代码 1 2 3 4 5 6 7 8 9 10 11 @Test public void testMBG () throws Exception { List<String> warnings = new ArrayList <String>(); boolean overwrite = true ; File configFile = new File ("mbg.xml" ); ConfigurationParser cp = new ConfigurationParser (warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback (overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator (config, callback, warnings); myBatisGenerator.generate(null ); }
2、逆向工程的使用 基本查询(查询全部数据) 1 2 3 4 5 6 7 8 9 @Test public void test2 () throws Exception { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); List<Emp> emps = mapper.selectByExample(null ); emps.forEach(System.out::println); }
带条件查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Test public void test1 () throws Exception { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); EmpExample empExample = new EmpExample (); EmpExample.Criteria c1 = empExample.createCriteria(); c1.andEnameLike("%a%" ); c1.andSexEqualTo("1" ); EmpExample.Criteria c2 = empExample.createCriteria(); c2.andDidEqualTo(2 ); empExample.or(c2); List<Emp> emps = mapper.selectByExample(empExample); for (Emp emp : emps) { System.out.println(emp); } }
八、扩展-PageHelper 分页插件 1、PageHelper 的使用步骤 导入相关包 pagehelper-x.x.x.jar 和 jsqlparser-0.9.5.jar 在 Mybatis 全局配置文件中配置分页插件 1 2 3 <plugins > <plugin interceptor ="com.github.pagehelper.PageInterceptor" > </plugin > </plugins >
2、Page 对象的使用 载查询之前通过 PageHelps.startPage(页码,条数)设置分页信息,该方法返回 Page 对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public SqlSessionFactory getsqlSessionFactory () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); return sqlSessionFactory; } @Test public void testPageHelps () throws IOException { SqlSessionFactory sqlSessionFactory = getsqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Page<Object> page = PageHelper.startPage(2 , 3 ); List<Emp> emps = mapper.getAllEmps(); emps.forEach(System.out::println); System.out.println("====================================================" ); System.out.println("当前页:" + page.getPageNum()); System.out.println("总页码:" + page.getPages()); System.out.println("总条数:" + page.getTotal()); System.out.println("每条显示的条数:" + page.getPageSize()); }
3、PageInfo 对象的使用 在查询完数据以后,使用 PageInfo 对象封装查询结果,可以获取更详细的分页信息以及完成分页逻辑 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Test public void testPageHelps1 () throws IOException { SqlSessionFactory sqlSessionFactory = getsqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true ); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Page<Object> page = PageHelper.startPage(2 , 3 ); List<Emp> emps = mapper.getAllEmps(); PageInfo<Emp> info = new PageInfo <>(emps, 5 ); for (Emp emp : emps) { System.out.println(emp); } System.out.println("===================================" ); System.out.println("当前页:" +info.getPageNum()); System.out.println("总页数:" + info.getPages()); System.out.println("每页显示的条数:" + info.getPageSize()); System.out.println("是否是第一页:" + info.isIsFirstPage()); System.out.println("是否显示最后一页:" + info.isIsLastPage()); System.out.println("是否有上一页:" + info.isHasPreviousPage()); System.out.println("是否有下一页:" + info.isHasNextPage()); System.out.println("======================================" ); int [] nums = info.getNavigatepageNums(); for (int num : nums) { System.out.print(num + " " ); } }