mybatis
1. mybatis的介绍
1.mybati是什么
是一个基于orm思想的优秀的持久层数据库框架 他就是ibatis的衍生 #### 2. mybatis能做什么 1. 框架学习简单,涉及的依赖和配置很少 2. mybatis相对于其他持久层框架编写sql更加灵活 3. mybatis支持动态sql,可以根据业务需求动态生成sql 4. mybatis还支持注解添加sql语句,添加语句更简单 5. mybatis不需要你做事务相关和资源的释放 6. mybatis有很强大的resultMap结果集映射标签,可以更简单的实现多表查询 7. mybatis支持跨平台命名规范 user_name as username 8. mybatis友好支持第三方插件,例如做分页 9. mybatis支持逆向工程,可以完成绝大部分的sql语句,实现查询; 10. mybatis支持来发人员任意修改sql语句,而hibernate只提供方法,不允许修改。 11. 官方文档齐全 #### 3. 什么是orm思想 1. 对象关系映射(Object Relational Mapping,简称ORM),将实体类通过元数据映射数据库中的具体表和行,开发人员只用面向对象思想进行编程就可。对象关系映射是通过使用描述对象和数据库之间映射的[元数据]将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示着额外的执行开销; ### 4.基于org思想的持久层框架的异同点 相同点: 1. 提供面向对象的数据库操作方法 save() update() 2. 帮助我们写sql语句,数据库方法-----orm映射---数据库crud ##### hibernate:全自动orm持久层框架 提供一套完整的数据库操作方法 提供所有方法对应的sql语句只需要学习有哪些方法,不用管理sql的执行 ##### mybatis:半自动持久层框架 提供完整的数据库操作方法 没有提供sql语句的实现 直接暴露sql 对应的mapper文件,可以随便修改,因此更加的灵活
2. mybatis的基本使用一个
步骤一:导入依赖
mybatis 3.4.5
mysql
cglib足够!!!myBatista的优点之一,只需要导入一个jar就可实现mybatis
步骤二:编写mybatis核心配置文件
<?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="db.properties"/> <settings> <!--驼峰命名与数据库字段匹配--> <setting name="mapUnderscoreToCamelCase" value="true"/> <!--<setting name="useGeneratedKeys" value="true"/>--> <!--此处有很多核心的全局数据库设置--> </settings> <!--起别名--> <typeAliases> <!--按照全类路径名起别名--> <!--<typeAlias type="com.it.mapper.BMapper" alias="b"/>--> <!--按照包起别名 默认包下的类名首字母小写--> <package name="com.it.pojo"/> </typeAliases> <!--数据库环境--> <environments default="dev"> <!--开发 测试 。。。--> <environment id="dev"> <!--事务管理 --> <transactionManager type="jdbc"></transactionManager> <!--连接池--> <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> <!--映射的mapper文件--> <mappers> <!--按照目录引入--> <!--<mapper resource="com/it/mapper.UserMapper.xml"/>--> <!--按照包名引入mapper文件--> <package name="com.it.mapper"/> </mappers> </configuration>
步骤三:编写mapper配置文件
<?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.it.mapper.AMapper">//namespace mapper的全类路径名 <!--执行sql语句标签 id必须要和接口中的方法名一样--> <insert id="insertA" keyColumn="a_id" keyProperty="aId" useGeneratedKeys="true" > <!--具体的sql语句--> insert into a(a_name) values(#{aName}) </insert> <select id="selectById" resultType="a"> select * from a where a_id=#{aid} </select> </mapper>
步骤四:编写编写测试
@Test public void testa() throws IOException { //获取核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); /** * 获取SqlsessionfactoryBuilder 此对象只用一次,因此放在局部就可以 * sqlsession只用一个,因此只用创建一个就可以了 */ SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder(); //获取sqlsessionfactory SqlSessionFactory factory = factoryBuilder.build(resourceAsStream); // //创建sqlsession 他是具体的执行对象 SqlSession sqlSession = factory.openSession(); //crud。。。 //ibatis和mybatis的使用区别,ibatis需要类,,命名空间可以随便写,就是为了区分而存在,并在执行语句中传入statment字符串,以及对象 //mybatis需要接口,接口名要和mapper文件的标签里面的id名称要相同, //提交 因为默认开启事务 sqlSession.commit(); sqlSession.close(); }
步骤五:在pom文件引入src下的xml配置文件
<resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources>
提取工具类方法
public class MybatisUtils { // 工厂 private static SqlSessionFactory factory =null; static { //输入流 InputStream resourceAsStream = null; try { // 读取配置文件 resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); } catch (IOException e) { e.printStackTrace(); } // 只用一次的创建对象 SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder(); factory = factoryBuilder.build(resourceAsStream); } // 获取方法 public static SqlSession openSqlSession(){ SqlSession sqlSession = factory.openSession(); return sqlSession; } //mybaits默认开启事务管理,因此需要提交和关闭 public static void commitAndClose(SqlSession sqlSession){ sqlSession.commit(); sqlSession.close(); } }
mybatis核心配置讲解
properties:
用来申明变量和引入外部配置文件的,例如数据库配置文件db.properties文件
//也可以申明内部property标签,如果内部属性名和外部相同,内部会覆盖掉外部配置
settings:(核心全局设置标签)
开启后台sql语句的输出
name就是属性 value就是对应的配置
//开启驼峰命名自动映射
默认不开启
指定应如何映射列与属性,
NONE|不映射
PARTIAL|没有嵌套的映射
FULL 默认PARTIAL:映射任意复杂的嵌套映射
使用日志
value:sef4j|log4j|conmmons-loging…
STDOUT_LOGGING输出sql在控制台
当所有列都是空,会返回一个null,当开启后,会返回一个空的对象
默认false
typeAliases:别名
typeAlias:按照全部类路径名 给类起别名
package按照包名给类起别名,就是包下的所有类默认类名首字母小写的形式别名
内置气的别名,基本类型首字母小写。。。
environments(环境配置)
environment(环境变量)
transactionManager(事务管理)
dataSource(数据源)
Mapper映射mapper.xml文件
可以根据目录映射
也可以根据包名映射
允许在插入时获取插入记录的主键信息
useGenaretedKeys 默认关闭
mapper文件配置
cache:对给定的命名空间缓存设置
cache-ref:对其他命名空间缓存设置
resultMap:复杂结果集的映射
sql:sql片段,为了简化大量的相同的代码块的重写冗余
insert…crud标签
crud里的属性
insert:
keyProperty =“属性id”
keyColumn =“列id”
useGenerateKeys=“true” 生成主键相关,在插入记录时候获取主键信息
timeOut=“20” statement语句的执行超时时间单位s
update:
flusheCahche=“true”
statementType=“PREPARED”…statment
delete:
3. mybatis的传参问题
- $和#的区别
$用来字符串的拼接#用来占位
写#就相当于要用statementType=“PREPARED”
例如:
<select id="queryAccountByCommonsParam" resultType="ergouzi"> select * from account where ${columnName} = #{value} </select>
- 传入单个参数时候
#{} ${} 里面的key可以任意写
- 多个参数时候时
默认一个方法传入多个参数时候无法通过${} #{} 获取到值
可以传入对象
在接口方法中类型是一个对象
$ 和 # 的引入必须和对象数据姓名一致
map的方式
方法传入map sql语句中引入map的key就可以
引入值必须是key
注解方式@Param(“具体名字”),¥{} #{}中名字必须要和@Param里面的一样
4. mybatis的主键生成策略
主键:
为了区分一条记录不重复的列
自然主键:本来有的属性,属性刚好符合唯一特性,我们可以看作逐渐(不推荐使用)
自定义主键:专门设置的一列,没有其他描述的含义。
主键一旦设定,不能修改,只能删除,新添加的主键不能沿用(无法在插入的对象中找到主键)。
数据类型(int,bigint,long)主键自动增长,auto_increment;
优点:自动增长,不需要维护。
字符串类型:
没有自动增长的属性,
uuid永远不重复,理论上无穷,需要自己维护
1. 数字类型的主键获取
<insert id="insertInfo" parameterType="Info"> insert into info (i_info,a_id) values (#{iInfo},#{aId}) </insert> @Test public void test6(){ SqlSession sqlSession = MybatisUtils.openSqlSession(); InfoMapper mapper = sqlSession.getMapper(InfoMapper.class); Info info = new Info(); info.setaId(1); info.setiInfo("良好品质,请放心购买"); int i = mapper.insertInfo(info); System.out.println("i = " + i); System.out.println("info = " + info); MybatisUtils.commitAndClose(sqlSession); } resoult: info = Info{iId=0, iInfo='良好品质,请放心购买', aId=1} 可以发现iId为空 获取主键: 修改: <insert id="insertInfo" parameterType="Info" keyColumn="i_id" keyProperty="iId" useGeneratedKeys="true"> insert into info (i_info,a_id) values (#{iInfo},#{aId}) </insert> //keyColumn为数据库主键名 keyProperty为实体类属性 //useGenerateKeys="true" 代表获取主键值 默认false 执行测试: result: info = Info{iId=8, iInfo='良好品质,请放心购买', aId=1} iId获取到了
2. 字符串类型的主键获取
<insert id="add" parameterType="User" > //插入primary keyColumn:主键名字 keyProperty:主键属性 //order :before在inser语句执行前后后执行 <selectKey keyColumn="i_id" keyProperty="uId" order="BEFORE" resultType="string"> select uuid();//生成唯一串 </selectKey> insert into user (u_id,uname,age) values (#{uId},#{uName},#{age}) </insert> @Test public void test7(){ SqlSession sqlSession = MybatisUtils.openSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setAge(12); user.setuName("珍君"); int add = mapper.add(user); System.out.println("add = " + add); System.out.println("user = " + user); MybatisUtils.commitAndClose(sqlSession); } result: user = User{uId='7425dfdc-fd6f-11e9-ae08-d017c2236ed4', uName='珍君', age=12} 主键在插入式就可以查出字符串属性值,因为他是插入方法之前执行的
5. mybatis核心resultMap
resultMap是mapper 中的一个标签,当resultType满足不了结果集映射时候就可以用resultMap
情景:当列名和属性名不一样的时候,
:列名和属性名不一致时的解决方案
1. 在查询语句中给列起别名
注意:当所有列都不匹配时候就会返回null
例如:select a_id aId ,a_name aName from a where a_id=#{aid}
2. sql语句片段
select a_id aId, a_name aName from
引入:
...3. mybtais开启自动识别映射功能(驼峰命名)
4. resultMap
嵌套结果集
使用连接查询,查询多表之间的信息,通过resultmap分别给属性进行赋值
<resultMap id="map" type="Category"> //主键用id标签 column 用于指定数据库列名 property:对应实体属性 <id column="c_id" property="cId"></id> //主表中有辅表类型的集合用collection propety 集合名字 ofType就是集合泛型 //其他列用result 标签column propety <collection property="products" ofType="Product"> <id column="p_id" property="pId"></id> </collection> </resultMap> //如果在字表中有主表的引用应该用association标签
5. mybatis核心resultMap多表查询
- 表关系分析
- 一对一:存在主外键,只不过外键是唯一或者外键直接作为主键
- 一对多:存在外间关系,外键没有限制
- 多对多:两个表之间没有直接关系,会创建一个中间表,中间表存在两个外键,分别关联两个表的主键。
- 数据库实体类设计:
面向对象思想射界实体类;子表中的主表信息应该是一个实体
例如:
(字表)
Product
pId;
pName;
cId;
category;
主表:
category;
cId;
cName;
List list;
主表里面含有子表的集合泛型
设计总结:
子表方:子表方存在主表的外键,外键就是关联主表方的一条记录的对象
所以我们设计字表对应的实体的时候,建议把外键列设计成主表的对象的引用,这样更容易的能获取到主表的数据
主表方:主表方没有直接关联子表但是可以通过主表的id去子表查询很多关联的字表信息
主表和子表也间接的产生了关联。如果有需求,主表中可以显示字表中的信息,就可以放子表的集合
嵌套结果集
就是利用连接查询,将结果一次性的全部查询出来,在resultmap中利用collection\association标签给属性赋值的过程
嵌套结果集的缺点
有时候在多表查询时,我们可能只需要查询一个表中的数据,但是查询除了所有表的信息
这样会降低查询效率。
嵌套查询(分步查询)
向下查询
@Test public void test8(){ SqlSession sqlSession = MybatisUtils.openSqlSession(); ProductMapper mapper = sqlSession.getMapper(ProductMapper.class); Product product = mapper.selectProductByPidQian(1); System.out.println("product = " + product); System.out.println("product.getCategory() = " + product.getCategory()); System.out.println("product.getInfo = " + product.getCategory().getInfo()); MybatisUtils.commitAndClose(sqlSession); } //在查询product时候触发category的查询 <!--嵌套查询--> <resultMap id="qiantaoproduct" type="Product"> <id column="p_id" property="pId"></id> <!--向下查询时候需要手动result--> <result column="c_id" property="cId"></result> <!--触发一个子查询,给category赋值,column根据哪一列作为参数传入到子查询中--> <association property="category" javaType="Category" column="c_id" select="com.it.mapper.CategoryMapper.selectCategoryByCid"> </association> </resultMap> <select id="selectProductByPidQian" resultMap="qiantaoproduct"> select * from product where p_id=#{pid} </select> <resultMap id="ct" type="Category"> <id column="c_id" property="cId"></id> <!--向下查询时候result不可以省略--> <result column="i_id" property="iId"></result> <!--并引入info的查询--> <association property="info" column="i_id" javaType="Info" select="com.it.mapper.InfoMapper.selectInfoByIid"> </association> </resultMap> <select id="selectCategoryByCid" resultMap="ct"> select * from category where c_id=#{cid} </select> 注意!!!! 在触发category的查询时候用了column 属性,用于给category的查询传参 并用select属性传入category查询方法的命名空间和方法名 并且再在category里面触发info的查询
向上查询:
@Test public void test10(){ SqlSession sqlSession = MybatisUtils.openSqlSession(); InfoMapper mapper = sqlSession.getMapper(InfoMapper.class); Info info = mapper.selectInfoAndCategoryAndProduct(1); System.out.println("----------------"); System.out.println("info = " + info); List<Category> categories = info.getCategories(); for (Category category : categories) { System.out.println("###############"); System.out.println(category); } MybatisUtils.commitAndClose(sqlSession); } <resultMap id="iAndCAndPro" type="Info"> <id column="i_id" property="iId"></id> <!--触发category的查询--> <collection property="categories" ofType="Category" column="i_id" select="com.it.mapper.CategoryMapper.selectCategoryAndProductByCid"> <id column="c_id" property="cId"></id> </collection> </resultMap> <select id="selectInfoAndCategoryAndProduct" resultMap="iAndCAndPro"> select * from info where i_id=#{iid} </select> <!--向上查询--> <resultMap id="cAndPro" type="Category"> <id column="c_id" property="cId"></id> <!--出发product的查询--> <collection property="products" ofType="Product" column="c_id" select="com.it.mapper.ProductMapper.selectProductByPid"> </collection> </resultMap> <select id="selectCategoryAndProductByCid" resultMap="cAndPro"> select * from category where c_id=#{cid} </select> result: ---------------- info = Info{iId=1, iInfo='零食好吃可不要贪杯哦', aId=1} ############### Category{cId=1, cName='零食', iId=1}
6. 动态sql
mybatis提供了一系列的标签,控制sql语句的结构,
<!--动态sql语句
根据传入的不同的参数二位执行不同的sql语句
-->
<select id="selectBlogs" resultType="Blog">
if标签!!!!!!!!!!!
1:需要在where后面添加永远成立条件
2:当只有永远成立条件成立时会查出所有的记录
3:当多个条件成立时会拼接多个条件
<!--select * from blog where 1=1
<if test="id != 0">
and id=#{id}
</if>
<if test="title != null">
and title=#{title}
</if>
<if test="content !=null">
and content=#{content}
</if>-->
where标签!!!!!!!!
1:标签里面的条件都不满足时候会查询所有信息:
2:会自动添加在表明后添加 where
3:当第一个条件满足时会自动忽略条件里面的and
<!--select * from blog
<where>
<if test="id != 0">
and id=#{id}
</if>
<if test="title != null">
and title=#{title}
</if>
<if test="content !=null">
and content=#{content}
</if>
</where>-->
select * from blog where
choose标签 !!!!!!!!
1:当所有的都不符合条件时会走othorwise,会查出所有
2:当有多个条件满足时会默认走最后一个判断,他不会对sql语句进行拼接
<choose>
<when test="id !=0">
id=#{id}
</when>
<when test="content !=null">
content =#{content}
</when>
<when test="title !=null">
title = #{title}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</select>
<foreach>遍历in
1:它可以遍历集合
2:可以遍历数组
集合:
</select>
<select id="selectBlogInids" resultType="Blog">
select * from blog where id in
<foreach collection="list" separator="," open="(" close=")" index="it" item="r">
#{r}
</foreach>
</select>
数组
<select id="selectBlogInids" resultType="Blog">
select * from blog where id in
<foreach collection="array" separator="," open="(" close=")" index="it" item="r">
#{r}
</foreach>
</select>
参数说明:
collection:是遍历的数据类型 list|array
separator是分隔符 括号里面的,
open:就是sql语句中的 in ()
close:结束括号
index:下标
item:就是每次便利的一条记录
7. mybatis注解形式进型sql语句编写
注解形式查询适合单表查询,虽然注解查询很简单,但是不建议注解形式查询,因为在xml形式的查询中有
注解形式的查询,不利于系统维护,
注解形式只要在方法上添加注解
@Select(" select * from product where p_id=#{pid}")
Product selectProductById(int pid)
@Delete(“delete from product where p_id=${pid}”)
int deleteProduct(int pId);
…
8.延迟加载
不在初始化的时候加载,需要等到对象的是属性、方法被调时候,才会被加载
只有嵌套查询时候才会有延迟加载(lazyLoadingEnabled),嵌套结果集没有延迟加载,因为嵌套结果集试一次查询,
触发条件:
有嵌套查询,嵌套查询中的column是传下去的查询条件,为子查询的主键id
查询结果被用时候才会触发被嵌套的查询,没有用时不会查询
lazyLoadingEnabled与aggressiveLazyLoading
aggressiveLazyLoading是按需求加载 积极加载
调用子属性,而且只调用子属性时才能实现单个查询。
ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
Product product = mapper.selectProduct(1);
System.out.println("product = " + product.getpName());
MybatisUtils.commitAndClose(sqlSession);
9. 缓存
#### 一级缓存
缓存:查询的获得的数据在某些情况下不会触发sql语句直接拿到结果,走缓存
他是默认缓存级别
获取缓存:
- 同一个sqlsession/
- 可以是同个session 但是不同的mapper
- 查询的id相同
- 两次查询之间不能有dml操作
Detail detail = mapper.selectDetailById(1);
System.out.println("detail = " + detail);
System.out.println("___________________");
Detail detail1 = mapper.selectDetailById(1);
System.out.println("detail1 = " + detail1);
MybatisUtils.commitAndClose(sqlSession);
result:
==> Preparing: select * from detail where d_id=?
==> Parameters: 1(Integer)
<== Columns: d_id, d_info
<== Row: 1, 好商品,格力造
<== Total: 1
detail = Detail{dId=0, dInfo='null'}
___________________
detail1 = Detail{dId=0, dInfo='null'}
可看出默认走的缓存:
不同mapper也是走缓存
不同sqlsessionFactory 不会走缓存
DetailMapper mapper = sqlSession.getMapper(DetailMapper.class);
Detail detail = mapper.selectDetailById(1);
System.out.println("detail = " + detail);
System.out.println("___________dml操作________");
detail.setdId(435);
detail.setdInfo("bfdkjlbk");
mapper.insertInto(detail);
DetailMapper mapper1 = sqlSession.getMapper(DetailMapper.class);
Detail detail1 = mapper1.selectDetailById(1);
System.out.println("detail1 = " + detail1);
result:
==> Preparing: select * from detail where d_id=?
==> Parameters: 1(Integer)
<== Columns: d_id, d_info
<== Row: 1, 好商品,格力造
<== Total: 1
detail = Detail{dId=0, dInfo='null'}
___________dml操作________
==> Preparing: insert into detail(d_id,d_info) values(?,?);
==> Parameters: 435(Integer), bfdkjlbk(String)
<== Updates: 1
==> Preparing: select * from detail where d_id=?
==> Parameters: 1(Integer)
<== Columns: d_id, d_info
<== Row: 1, 好商品,格力造
<== Total: 1
detail1 = Detail{dId=0, dInfo='null'}
证明中间有mdl 操作不会走缓存,要经过sql 语句
二级缓存
默认二级缓存是关闭的
获取缓存:
-
同一个sqlsessionFactory
-
默认情况下二级缓存是关闭的,因为参与的用户很多,可能出现很多数据安全问题
-
只要两次查询时间没有dml操作清空缓存
-
不同的sqlsession和mapper都可以有缓存
学习点:
-
如何开启二级缓存
默认是开起的但是每个mapper文件中又关闭着二级缓存。因此在mapper配置文件中写
-
如何这只特定的sql情况
开启缓存最大的隐患就是并发情况下获取到了脏数据
情景:后台更新频繁的数据,不建议开启二级缓存
数据更新不是很频繁时候建议开启二级缓存,例如首页的轮播图
或者类别,菜单等
mapper开启缓存,但是内部特定方法关闭二级缓存
-
面试问题:mybatis缓存有什么优势
缓存颗粒度更细:
能控制单个查询方法:usecache:true:开启直接获取缓存不取再查询
false:关闭,直接去查询,不去走缓存,也不会存入缓存
flushcache 刷新缓存,true 先查询新的数据,存入缓存,在缓存中获取数据
false:不刷新。
-
总结:二级缓存总开关,每个mapper文件的缓存开关,具体的方法的缓存开关,因此颗粒度小,这是他的一个优点。但是到缓存满了后他会删除缓存,而且用的算法是先进先出类型的,不管活跃度,直接删除,这就是我们为设么一般用第三方缓存的原因
-
一般情况下我们会用第三方缓存
-
导入依赖:
net.sf.ehcache ehcache-core 2.6.5 org.mybatis mybatis-ehcache 1.0.0 -
开启缓存开关
1.核心配置文件
2.mapper写cache标签
-
在classpath路径下!写一个cache.xml的缓存配置文件
LRU:算法! 最近 最少 使用
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法
maxElementsInMemory 超过内存缓存存储数量以后!注意不会再缓存!而不是清空!lru
lur:当扫描时间到的时候!会统一 算。
<ehcache > <!-- 缓存数据要存放的磁盘地址 --> <diskStore path="D:\develop\ehcache" /> <!-- diskStore:指定数据在磁盘中的存储位置。 defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略 以下属性是必须的: maxElementsInMemory - 在内存中缓存的element的最大数目 maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大 eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断 overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 以下属性是可选的: timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大 timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区. diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作 memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) --> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
在缓存满了后会写文件到本地磁盘里面,因此用到了序列化的问题,因此实体类需要实现序列化接口
-
10.
mybatis分页插件!只需要你正常查询全部sql语句!设置当前页数和页容量!
即可获取所有分页先关的数据!例如:当前页的数据集合!第几页!页容量!中页数!上一页下一页!等等!
使用分页插件
写分页插件的依赖
com.github.pagehelper pagehelper 4.1.6核心配置文件中添加插件
直接食用分页插件就行
1.设置分页信息(第几页,页容量)
2.查询所有的信息(不用分页查询 limit) 3.创建PageInfo 4.获取分页信息 //分页查询了 //1.设置分页信息 PageHelper.startPage(index, size); SqlSession sqlSession = MybatisUtils.openSqlsession(); ProductMapper mapper = sqlSession.getMapper(ProductMapper.class); List<Product> products = mapper.selectProductAll(); PageInfo<Product> pageInfo = new PageInfo<>(products);
MybatisUtils.commitAndClose(sqlSession);
//获取所有信息 List<Product> list = pageInfo.getList(); System.out.println("当前页的数据" ); for (Product product : list) { System.out.println("product = " + product); } int pageNum = pageInfo.getPageNum(); System.out.println("获取当前页 = " + pageNum); boolean hasNextPage = pageInfo.isHasNextPage(); System.out.println("是否有下一页 = " + hasNextPage); if (hasNextPage) { int nextPage = pageInfo.getNextPage(); System.out.println("下一页 = " + nextPage); }
boolean hasPreviousPage = pageInfo.isHasPreviousPage(); System.out.println("是否有上一页 = " + hasPreviousPage); if (hasPreviousPage) { int prePage = pageInfo.getPrePage(); System.out.println("上一页 = " + prePage); }
long total = pageInfo.getTotal(); System.out.println("总条数 = " + total);
int pages = pageInfo.getPages(); System.out.println("总页数 = " + pages); int pageSize = pageInfo.getPageSize(); System.out.println("页容量 = " + pageSize);