MyBatis简介 MyBatis是一个持久化框架(ORM),它原本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。相对于同样实现持久化功能的Hibernate 而言,它更轻量级、学习成本更低、可控性更高。尤其是改名为MyBatis后,框架整体做了较大的改进,渐渐成为能与Hibernate比肩的持久化框架。
与Hibernate不同MyBatis的核心思想不是“对象关系映射”,而是“对象查询映射”。程序员需要自己编写SQL语句来实现Java对象与数据库的转换,因此在编码量上较Hibernate大,但在性能、可控性和易用性上却比Hibernate更好。
ORM(Object Relational Mapping):对象关系映射 编写程序的时候,以面向对象的方式处理数据,保存数据的时候,却以关系型数据库的方式存储。 持久化的操作:将对象保存到关系型数据库中 ,将关系型数据库中的数据读取出来以对象的形式封装
学习文档 相对与其它框架,MyBatis的使用相对比较简单,MyBatis框架和工具可以在google code上下载:https://code.google.com/p/mybatis
MyBatis官方配有中文翻译的使用文档:http://mybatis.github.io/mybatis-3/zh/index.html
后续学习MyBatis-Plus
:https://baomidou.com/
书籍下载:https://pengyirui.lanzoui.com/iF6c1wcdl7a
导包 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 48 49 50 51 <dependencies > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.6</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.1</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.17</version > </dependency > </dependencies > <build > <plugins > <plugin > <artifactId > maven-compiler-plugin</artifactId > <groupId > org.apache.maven.plugins</groupId > <configuration > <source > 1.8</source > <target > 1.8</target > </configuration > </plugin > </plugins > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > </resource > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.xml</include > <include > **/*.properties</include > </includes > </resource > </resources > </build > </project >
创建MyBatis主配置文件(配置SqlSession工厂) 在src
目录下创建名为mybatis-config.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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 <?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 > <properties resource ="jdbc.properties" > </properties > <typeAliases > <typeAlias type = "io.peng.demo.pojo.Users" alias ="users" /> </typeAliases > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="${jdbc.driverClassName}" > </property > <property name ="url" value ="${jdbc.url}" > </property > <property name ="username" value ="${jdbc.username}" > </property > <property name ="password" value ="${jdbc.password}" > </property > </dataSource > </environment > </environments > <mappers > <mapper resource ="StudentMapper.xml" > </mapper > </mappers > </configuration >
创建实体类及实体映射文件(Mapper/Dao) 例子: 创建数据实体类Category.java
和实体映射文件Category.xml
。
每添加一个实体配置文件,就应该在主配置文件(mybatis-config.xml)中加入一个元素,以告知框架要把该实体加入到映射中。
1 2 3 4 5 6 7 8 9 10 <?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.powernode.dao.CategoryDao" > <select id ="getAll" resultType ="com.powernode.model.Category" > select * from category </select > </mapper >
测试,创建MyBatis会话(SqlSession)并执行查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void getAll () { try { InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory factory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession=factory.openSession(); List<Category> list=sqlSession.selectList("getAll" ); for (Category category : list) { System.out.println(category.getName()); } }catch (Exception ex){ System.out.println(ex.getMessage()); } }
上述代码中:
SqlSessionFactoryBuilder
:用于构建SqlSessionFactory,此后这个类就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围 (也就是本地方法变量)。
SqlSessionFactory
:一旦被创建,应该在你的应用执行期间都存在。没有理由来处理或重 新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次,因此 SqlSessionFactory 的最佳范围是应用范围,最简单的就是使用单例模式或者静态单例模式。
SqlSession
:每个线程都应该有它自己的SqlSession实例。SqlSession 的实例不能被共享,它是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将 SqlSession 实例的引用放在一个类的静态字段甚至是实例字段中。如果你在使用Web框架,则要考虑把SqlSession 放在一个和HTTP请求对象相似的范围内(Open Session In View)。关闭 Session 很重要,你应该确保使 用 finally 块来关闭它。
配置日志功能 mybatis.xml
文件加入日志配置,可以在控制台输出执行的 sql 语句和参数
1 2 3 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings >
log4j配置
导入log4j的包
修改配置
1 2 3 <settings > <setting name ="logImpl" value ="LOG4J" /> </settings >
在resources
目录下添加log4j.properties
文件
1 2 3 4 5 6 7 8 9 log4j.rootLogger =debug, stdout,logfile log4j.appender.stdout =org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target =System.err log4j.appender.stdout.layout =org.apache.log4j.SimpleLayout log4j.logger.java.sql.ResultSet =INFO log4j.appender.logfile =org.apache.log4j.FileAppender log4j.appender.logfile.File =d:/mylog.log log4j.appender.logfile.layout =org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern =%d{yyyy-MM-dd HH\:mm\:ss} %l %F %p %m%n
封装工具类MyBatisUtil类 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 public class MyBatisUtil { private static SqlSessionFactory factory = null ; static { try { String config = "mybatis-config.xml" ; InputStream in = Resources.getResourceAsStream(config); factory = new SqlSessionFactoryBuilder ().build(in); } catch (Exception e) { factory = null ; e.printStackTrace(); } } public static SqlSession getSqlSession () { SqlSession session = null ; if (factory != null ) { session = factory.openSession(); } return session; } }
工具类+接口 在之前的数据库查询中,使用映射语句com.mycinema.model.Category.getAll
指定要执行的SQL,这种做法有些弱点:缺乏编译检查。为此,MyBatis还提供了映射器的执行方法。
getMapper 获取代理对象 只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao 接口类的 class 值。
1 2 SqlSession session = factory.openSession(); CategoryDao categoryDao= session.getMapper(CategoryDao.class);
使用Mapper接口实现数据访问 编写数据访问的接口
1 2 3 public interface CategoryDao { List<Category> getAll () ; }
编写数据访问类的映射文件(在目录:resource/mapper/CategoryDao.xml
)
1 2 3 4 5 6 7 8 9 10 <?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.powernode.dao.CategoryDao" > <select id ="getAll" resultType ="com.powernode.model.Category" > select * from category </select > </mapper >
注意 :其中方法CategoryDao中的(getAll)的签名与配置的select元素相同。
此后,我们就可以通过CategoryDao接口实现前面的查询了:
1 2 3 4 5 6 SqlSession sqlSession=factory.openSession(); CategoryDao categoryDao= sqlSession.getMapper(CategoryDao.class); List<Category> list=categoryDao.getAll(); for (Category category : list) { System.out.println(category.getName()); }
这种调用方式是强类型的,更为对象化,不容易出错,但是需要编写额外的Mapper接口。
动态代理 动态代理开发规范 MyBatis框架使用动态代理的方式来进行数据库的访问. Mapper接口的开发相当于是过去的Dao接口的开发。由MyBatis框架根据接口定义创建动态代理对象,代理对象的方法体同Dao接口实现类的方法。在设计时要遵守以下规范.
Mapper接口与Mapper.xml文件在同一个目录下(未必。。)
Mapper接口的完全限定名与Mapper.xml文件中的namespace的值相同。
Mapper接口方法名称与Mapper.xml中的标签的statement 的ID完全相同。
Mapper接口方法的输入参数类型与Mapper.xml的每个sql的parameterType的类型相同
Mapper接口方法的输出参数与Mapper.xml的每个sql的resultType的类型相同。
Mapper文件中的namespace的值是接口的完全限定名称.
在SqlMapConfig.xml文件中注册时,使用class属性=接口的完全限定名.
一句话:UsersMapper.java接口和UsersMapper.xml文件必须在同一个目录下,且必须同名。 在UsersMapper.xml文件中添加namespace属性为接口的完全路径名。
#{}和${} #{}
是对非字符串拼接的参数的占位符 ,如果入参是简单数据类型,#{}里可以任意写,但是如果入参是对象类型,则#{}里必须是对象的成员变量的名称,可以有效防止sql注入。
${}
主要是针对字符串拼接替换 ,如果入参是基本数据类型,${}里必须是value,但是如果入参是对象类型,则${}里必须是对象的成员变量的名称。可以替换列名和表名,存在sql注入风险,尽量少用。
返回主键标签 在完成插入操作后,将生成的主键信息通过实体类对象返回,在进行后继关联插入操作时,不用再次访问数据库
方式一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <insert id ="insertUser" parameterType ="com.oracle.demo.pojo.Users" > <selectKey order ="AFTER" keyProperty ="uid" resultType ="int" > select LAST_INSERT_ID() </selectKey >
动态sql <sql>标签
当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用。
1 2 3 <sql id ="columns" > id,username,birthday,sex,address </sql >
<include>标签
以为select为例调用<sql>标签
1 2 3 4 5 6 7 <select id ="getByCondiition" parameterType ="users" resultType ="users" > select <include refid ="columns" /> from users </select >
<choose>标签
有时候,我们不需要使用到所有的条件,只要满足其中的一个条件即可。<choose>
元素为此而生,它类似 Java 的 switch
语句,具有高度的相似性。choose
元素就好比 switch
在最外层,<choose>
元素下还有<when>
及<otherwise>
两个元素,<when>
元素类似于case
,而<otherwise>
则类似于default
。 例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <select id ="selectCount" resultType ="java.lang.Integer" > SELECT COUNT(*) FROM project_development pd LEFT JOIN business_customer bc ON bc.id = pd.customer_id LEFT JOIN base_project bp ON bp.id = pd.project_id WHERE pd.WORK = 1 <if test ="id != null" > and pd.id = #{id} </if > <choose > <when test ="sort != null" > order by pd.sort desc,pd.name </when > <otherwise > order by pd.start_date desc,pd.status desc,pd.progress desc,pd.id desc </otherwise > </choose > </select >
当 sort参数不为空时,执行 元素下的排序,元素可以同时存在多个,满足其中一个条件时就执行相应的sql,然后跳出,当所有都不满足时,则执行下的sql。
<if>标签
test:判断条件,如果test
为true则执行
1 2 3 <if test ="userName != null" > and username like '%${userName}%' </if >
不生效问题:这种情况不生效,原因是mybatis是用OGNL表达式来解析的,在OGNL的表达式中,“0”会被解析成字符(而我传入的type却是string),java是强类型的,char
和 string
会导致不等,所以if标签中的sql不会被解析。
解决办法:
1 2 3 4 5 6 7 8 9 <if test ="type == '1'.toString()" > </if > <if test ='type == "1"' > </if >
<where>标签 + <if>标签
一般开发复杂业务的查询条件时,如果有多个查询条件,通常会使用<where>
标签来进行控制。 标签可以自动的将第一个条件前面的逻辑运算符 (or ,and) 去掉,正如代码中写的,id 查询条件前面是有“and”关键字的,但是在打印出来的 SQL 中却没有,这就是 的作用。
1 2 3 4 5 6 7 8 9 <select id ="getByCondiition" parameterType ="users" resultType ="users" > select <include refid ="columns" > </include > from users <where > <if test ="userName != null" > and username like '%${userName}%' </if > </where > </select >
<set>标签
常用于更新 使用 if+set
标签修改后,在进行表单更新的操作中,哪个字段中有值才去更新,如果某项为 null 则不进行更新,而是保持数据库原值。切记:至少更新一列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <update id ="updateSet" parameterType ="users" > update users <set > <if test ="userName != null" > username=#{userName}, </if > <if test ="birthday != null" > birthday = #{birthday}, </if > <if test ="sex != null" > sex = #{sex}, </if > <if test ="address != null" > address = #{address} </if > </set > where id = #{id} </update >
<foreach>标签
<foreach>
主要用来进行集合或数组的遍历,主要有以下参数: collection:collection
属性的值有三个分别是 list、array、map
三种,分别对应的参数类型为:List、数组、map 集合。
item
:循环体中的具体对象。支持属性的点路径访问,如item.age,item.info.details
,在list和数组中是其中的对象,在map中是value。
index
:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。open
:表示该语句以什么开始close
:表示该语句以什么结束separator
:表示元素之间的分隔符,例如在in()的时候
循环遍历参数集合 1 2 3 4 5 6 7 8 <select id ="getByIds" resultType ="users" > select <include refid ="columns" > </include > from users where id in <foreach collection ="list" item ="id" separator ="," open ="(" close =")" > #{id} </foreach > </select >
批量删除 1 2 3 4 5 6 <delete id ="deleteBatch" > delete from users where id in <foreach collection ="array" item ="id" close =")" open ="(" separator ="," > #{id} </foreach > </delete >
批量增加 1 2 3 4 5 6 <insert id ="insertBatch" > insert into users(username,birthday,sex,address) values <foreach collection ="list" separator ="," item ="u" > (#{u.userName},#{u.birthday},#{u.sex},#{u.address}) </foreach > </insert >
批量更新 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <update id ="updateSet" > <foreach collection ="list" item ="u" separator =";" > update users <set > <if test ="u.userName != null" > username=#{u.userName}, </if > <if test ="u.birthday != null" > birthday = #{u.birthday}, </if > <if test ="u.sex != null" > sex = #{u.sex}, </if > <if test ="u.address != null" > address = #{u.address} </if > </set > where id = #{u.id} </foreach > </update >
注意:要使用批量更新,必须在url中添加&allowMultiQueries=true,允许多行操作。
入参也能循环 1 2 void addUserRoles (@Param("userId") int userId, @Param("roleIds") int [] roleIds) ;
1 2 3 4 5 6 7 <insert id ="addUserRoles" > insert into userRole(userId,roleId) values <foreach collection ="roleIds" separator ="," item ="rid" > (#{userId}, #{rid}) </foreach > </insert >
指定参数位置 可以不使用对象的属性名进行参数值绑定,使用下标值。 mybatis-3.3 版本和之前的版本使用#{0}
,#{1}
方式, 从 mybatis3.4 开始使用#{arg0}
方式。
UsersMapper.java接口中:
1 2 List<Users> getByBirthday (Date begin, Date end) ;
UsersMapper.xml文件中:
1 2 3 <select id ="getByBirthday" resultType ="users" > select * from users where birthday between #{arg0} and #{arg1} </select >
@Param指定参数名称 UsersMapper.java接口中:
1 2 3 4 List<Users> getByColunm (@Param("columnName") String columnName, @Param("columnValue") String columnValue) ;
UsersMapper.xml文件中:
1 2 3 4 5 <select id ="getByColunm" resultType ="users" > select <include refid ="columns" > </include > from users where ${columnName} =#{columnValue} </select >
入参是map 入参是map,是因为当传递的数据有多个,不适合使用指定下标或指定名称的方式来进行传参,又加上参数不一定与对象的成员变量一致,考虑使用map集合来进行传递。 map使用的是键值对的方式.当在sql语句中使用的时候#{键名},${键名},用的是键的名称。
UsersMapper.java接口中
1 2 List<Users> getByMap (Map<String,Date> map) ;
UsersMapper.xml文件中:
1 2 3 4 5 <select id ="getByMap" parameterType ="map" resultType ="users" > select <include refid ="columns" > </include > from users where birthday between #{zarbegin} and #{zarend} </select >
测试类中
1 2 3 4 5 6 7 8 9 10 11 @Test public void testGetByMap () throws Exception{ Date begin = new SimpleDateFormat ("yyyy-MM-dd" ).parse("1996-01-01" ); Date end = new SimpleDateFormat ("yyyy-MM-dd" ).parse("1998-12-31" ); Map<String,Date> map = new HashMap <>(); map.put("zarbegin" ,begin); map.put("zarend" ,end); List<Users> list = mapper.getByMap(map); list.forEach(u-> System.out.println(u)); }
返回值是map 返回值是map的适用场景,如果的数据不能使用对象来进行封装,可能查询的数据来自多张表中的某些列,这种情况下,使用map,但是map的返回方式破坏了对象的封装,返回来的数据是一个一个单独的数据, 之间不相关.map使用表中的列名或别名做为键名进行返回数据.
map封装返回值是一行 UsersMapper.java接口中:
1 2 Map<String,Object> getReturnMapOne (int id) ;
UsersMapper.xml文件中:
1 2 3 4 5 <select id ="getReturnMapOne" resultType ="map" parameterType ="int" > select id myid,username myusername,sex mysex,address myaddress,birthday mybirthday from users where id=#{id} </select >
测试类中:
1 2 3 4 5 6 @Test public void testGetReturnMapOne () { Map<String,Object> map = mapper.getReturnMapOne(7 ); System.out.println(map); System.out.println(map.get("username" )); }
返回值是map多行 UsersMapper.java接口中:
1 2 List<Map<String,Object>> getReturnMap () ;
UsersMapper.xml文件中:
1 2 3 4 <select id ="getReturnMap" resultType ="map" > select <include refid ="columns" > </include > from users </select >
测试类中:
1 2 3 4 5 @Test public void testGetReturnMap () { List<Map<String,Object>> list = mapper.getReturnMap(); list.forEach(map-> System.out.println(map)); }
列名与类中成员变量名称不一致 解决方案一: 使用列的别名,别名与类中的成员变量名一样,即可完成注入。
解决方案二: 使用<resultMap>
标签进行映射。
结果集映射 如果对象和表之间有更复杂的差异,比如Java对象中内嵌其它对象属性(多对一或一对多),就需要在MyBatis的实体配置文件中使用resultMap元素描述映射细节。
多对一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Movie { private int id; private String title; private String movieCode; private Category category; private String director; private Date dateReleased; …… } public class Category { private int id; private String name; …… }
这种情况下,若仅仅配置返回resultType
为Movie
类型的查询,则无法 返回外键对象Category
的数据:
1 2 3 < select id= "fetchById" parameterType= "int" resultType= "com.powernode.model.Movie"> select * from Movie where id = #{id} < / select >
这时,可以使用<select>
元素中resultMap
属性替代resultType
属性,配置对象的映射。resultMap元素是MyBatis中最重要最强大的元素,让你远离90%的需要从结果集中取出数据的JDBC代码,通过配置实现Java对象属性和查询结果字段的所有映射。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <resultMap type ="Movie" id ="movieResultMap1" > <id column ="id" property ="id" /> <result column ="title" property ="title" /> <result column ="movieCode" property ="movieCode" /> <result column ="director" property ="director" /> <result column ="dateReleased" property ="dateReleased" /> <association property ="category" column ="categoryId" javaType ="Category" select ="io.peng.model.Category.fetchById" > </association > </resultMap > <select id ="fetchById " parameterType ="int" resultMap ="movieResultMap1" > select * from Movie where id = #{id} </select >
以下是resultMap中重要子元素的解析:
子元素
作用
id
一个 ID 结果;标记结果作为 ID 可以帮助提高整体效能。
result
注入到字段或 JavaBean 属性的普通结果
association
一个复杂的类型关联;许多结果将包成这种类型嵌入结果映射
collection
复杂类型的集嵌入结果映射
column
sql语句上的 (select语句)
property
java对象实体上的
在这里,association元素实现了Movie和Category对象的多对一关系。 其中,select属性指定了另一个映射文件Category.xml中通过Id获取Category对象的查询。
在实际应用中,这种通过select属性获取关联对象的方式实际上产生了两条SQL语句, 第一条SQL查询Movie对象本身,第二条SQL通过外键categoryId查询Category对象。若某Movie查询返回N条Move记
如果使用SQL连接(Join)的方式,只需要一次查询即可,MyBatis中完全可以使用后者完成Movie数据的加载。 在<select>
元素中配置一个连接查询SQL语句,并在<resultMap>
的<association>
中进一步描述Category的映射。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <resultMap type ="Movie" id ="movieResultMap2" > <id column ="mid" property ="id" /> <result column ="title" property ="title" /> <result column ="movieCode" property ="movieCode" /> <result column ="director" property ="director" /> <result column ="dateReleased" property ="dateReleased" /> <association property ="category" column ="categoryId" javaType ="Category" > <id column ="cid" property ="id" /> <result column ="name" property ="name" /> </association > </resultMap > <select id ="fetchById " parameterType ="int" resultMap ="movieResultMap2" > select m.*, c.*, m.id as mid, c.id as cid from Movie m inner join Category c on m.categoryId=c.id where m.id=#{id} </select >
值得注意的是,MyBatis依靠查询结果集中的字段名来加载对象属性, 若两个连接的表字段同名(如id)时,需要用声明别名来完成映射(column=mid)。
一对多 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <select id ="selectAll" resultMap ="UserType" > SELECT u.id uid, u.username,u.`Password`,u.status, r.id rid, r.name FROM USER u INNER JOIN userrole ur ON u.`Id`=ur.`UserId` INNER JOIN role r ON r.`Id`=ur.`RoleId` </select > <resultMap id ="UserType" type ="User" > <id property ="id" column ="uid" /> <result property ="username" column ="username" /> <result property ="password" column ="password" /> <result property ="status" column ="status" /> <collection property ="roles" javaType ="Role" > <id property ="id" column ="rid" /> <result property ="name" column ="name" /> </collection > </resultMap >
缓存 mybaits提供一级缓存和二级缓存。默认开启一级缓存。
机制 在进行数据库访问时,首先去访问缓存,如果缓存中有要访问的数据,则直接返回客户端,如果没有则去访问数据库,在库中得到数据后,先在缓存放一份,再返回客户端。
一级缓存 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。如果sqlSession去执行commit操作(执行插入、更新、删除),则清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。如果没有重复第一次查询操作。
二级缓存 mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存,并且要让实体类实现serializable接口。
逆向工程插件 作用:快速生成 与表对照的实体类与XXXmapper.xml文件
逆向工厂跑第二次时要删除干净第一次生成的文件(XXXXXmapper.xml默认追加)
在maven文件的<build>
标签下添加插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <build > <finalName > provider</finalName > <plugins > <plugin > <groupId > org.mybatis.generator</groupId > <artifactId > mybatis-generator-maven-plugin</artifactId > <version > 1.3.7</version > <configuration > <configurationFile > GeneratorMapper.xml</configurationFile > <verbose > true</verbose > <overwrite > true</overwrite > </configuration > </plugin > <plugin > <artifactId > maven-compiler-plugin</artifactId > <version > 3.8.0</version > </plugin > </plugins > </build >
此文件与maven文件放在同级目录下 根据实际情况修改
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <?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 > <classPathEntry location ="C:\Empolder\mvn-repository\mysql\mysql-connector-java\5.1.6\mysql-connector-java-5.1.6.jar" /> <context id ="tables" targetRuntime ="MyBatis3" > <commentGenerator > <property name ="suppressAllComments" value ="true" /> </commentGenerator > <jdbcConnection driverClass ="com.mysql.jdbc.Driver" connectionURL ="jdbc:mysql://127.0.0.1:3306/mycinema" userId ="root" password ="123456" > </jdbcConnection > <javaModelGenerator targetPackage ="io.peng.mycinema.pojo" targetProject ="src\main\java" > <property name ="enableSubPackages" value ="false" /> <property name ="trimStrings" value ="false" /> </javaModelGenerator > <sqlMapGenerator targetPackage ="/" targetProject ="src\main\resources\mapper" > <property name ="enableSubPackages" value ="false" /> </sqlMapGenerator > <javaClientGenerator type ="XMLMAPPER" targetPackage ="io.peng.mycinema.mapper" targetProject ="src/main/java" > <property name ="enableSubPackages" value ="false" /> </javaClientGenerator > <table tableName ="category" domainObjectName ="Category" enableCountByExample ="false" enableUpdateByExample ="false" enableDeleteByExample ="false" enableSelectByExample ="false" selectByExampleQueryId ="false" /> <table tableName ="movie" domainObjectName ="Movie" enableCountByExample ="false" enableUpdateByExample ="false" enableDeleteByExample ="false" enableSelectByExample ="false" selectByExampleQueryId ="false" /> </context > </generatorConfiguration >
过滤器 设置编码用
新建类,实现Filter接口