二级缓存使用:
<mapper namespace="com.zhj.dao.UserDAO"> <!-- 当前mapper中的所有查询,都进入二级缓存 缓存数据中涉及的pojo一定要实现 Serialiable。 --> <cache></cache> <select>...</select> ..... </mapper> UserDAO userDAO1 = sqlSession1.getMapper(UserDAO.class); UserDAO userDAO2 = sqlSession2.getMapper(UserDAO.class); userDAO1.queryOne(1); userDAO2.queryOne(1); // 在开启了二级缓存的情况下,如上代码依然会查询两次数据库。 // userDAO1.queryOne(1);之后缓存只在sqlSession1中,并未进入二级缓存。userDAO2.queryOne(1);无法使用 UserDAO userDAO1 = sqlSession1.getMapper(UserDAO.class); UserDAO userDAO2 = sqlSession2.getMapper(UserDAO.class); userDAO1.queryOne(1); sqlSession1.commit();//close()也可以,因为close内部流程和commit内部流程有对缓存的相同处理 userDAO2.queryOne(1); // 此时如上代码会只查询一次数据库。 // sqlSession1.commit();执行时,会将查到的数据序列化,存入二级缓存中。userDAO2.queryOne(1)可以使用思考题:如下代码会如何查询数据库 ?
SqlSession sqlSession = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); SqlSession sqlSession3 = sqlSessionFactory.openSession(); UserDAO userDAO= sqlSession.getMapper(UserDAO.class); UserDAO userDAO2= sqlSession2.getMapper(UserDAO.class); UserDAO userDAO3= sqlSession3.getMapper(UserDAO.class); userDAO.queryOne(1); userDAO.queryOne(2); sqlSession.close(); userDAO2.queryOne(3); sqlSession2.close(); userDAO3.queryOne(1); userDAO3.queryOne(2); userDAO3.queryOne(3); //请分析如上查询,会触发哪些数据库查询 2.3 结构 二级缓存存储结构2.4 清除
二级缓存是以 namespace 为单位组织的,当某个 namespace 中发生数据改动,则 namespace 中缓存的所有数据会被mybatis清除。
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis_config.xml")); SqlSession sqlSession = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); SqlSession sqlSession3 = sqlSessionFactory.openSession(); UserDAO userMapper = sqlSession.getMapper(UserDAO.class); UserDAO userMapper2 = sqlSession2.getMapper(UserDAO.class); UserDAO userMapper3 = sqlSession3.getMapper(UserDAO.class); userMapper.queryUserById(1); sqlSession.close();//二级缓存生效 // userMapper中的所有二级缓存被清除 userMapper2.updateUser(new User(1,"zs",true,new Date())); sqlSession2.commit(); // 再次查询,二级缓存中已没有数据,会查询数据库 userMapper3.queryUserById(1); 2.5 cache-ref和关系属性相关
注意如果<collection>中没有使用select关联查询,则不存在此问题。
<mapper namespace="com.zhj.dao.UserDAO"> <cache/> <resultMap type="User"> <id property="id" column="uid"/> <result property="name" column="name"/> <result property="gender" column="gender"/> <result property="registTime" column="registTime"/> <collection property="orders" select="com.zhj.dao.OrderDAO.queryOrderOfUser" column="id" fetchType="eager/lazy"/> </resultMap> <select parameterType="int" resultMap="user_orders"> select id,name,gender,regist_time as registTime from t_user where id=#{id} </select> </mapper> <mapper namespace="com.zhj.dao.OrderDAO"> <!-- 使用cache-ref 则OrderDAO的缓存数据,会存放于com.zhj.dao.UserDAO分支下, 与UserDAO的缓存数据存储于同一个Perpetual对象中 --> <cache-ref namespace="com.zhj.dao.UserDAO"/> <select parameterType="int" resultType="Order"> select id as oid,note,price,create_time as createTime from t_order where user_id = #{userId} </select> </mapper> UserDAO userDAO = sqlSession1.getMapper(UserDao.class); //User 和 关系属性Order 都被缓存 User user = userDAO.queryOne(1); user.getOrders().size(); sqlSession.commit(); OrderDAO orderDAO = sqlSession2.getMapper(OrderDAO.lass); orderDAO.queryOrderOfUser(1); //有二级缓存数据可用 (OrderDAO中必须有 <cache>或<cache-ref>) UserDAO userDAO = sqlSession1.getMapper(UserDao.class); userDAO.queryOne(1); //数据改动,此时会清空User缓存,并清空Order缓存(因为order中是 <cache-ref>,如果是<cache>则此处只会清空User缓存) userDAO.insertUser(new User(null,"new_user",true,new Date())); sqlSession.commit(); OrderDAO orderDAO = sqlSession2.getMapper(OrderDAO.lass); orderDAO.queryOrderOfUser(1); //重新查询数据库 十、PageHelper 1. 使用过程 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>RELEASE</version> </dependency> <!-- plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下: properties?, settings?, typeAliases?, typeHandlers?, objectFactory?,objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers? --> <plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- 页号自动回归到合理数值 --> <property value="true"/> </plugin> </plugins> <!-- spring等价配置 <bean> <property> <array> <bean></bean> </array> </property> </bean> --> //使用: PageHelper.startPage(2,3);// 第2页,每页3条数据,pageNum,pageSize PageHelper.orderBy("id desc");//可以选择设置排序(可选) List<User> users = mapper.queryAllUsers();//PageHelper后的第一个查询语句,会被PageHelp增强处理(可观测mysql日志) for (User user : users) {// users中已经是分页数据 System.out.println(user); } //包装一个PageInfo,其中会持有所有分页会用到的信息:当前页号,每页多少条,共多少页,是否为第一页/最后一页,是否有下一页等。 PageInfo<User> pageInfo=new PageInfo<User>(users); PageInfo对象 概览注意:如果是多表查询,则会有如下效果: select t_user.id,name,gender,regist_time, t_order.id orderId,price,note,create_time from t_user JOIN t_order ON t_user.id = t_order.user_id LIMIT 2, 2 #是对大表做了分页,此时数据可能不完整,比如用户有10个订单,却只能查到2个,或部分。 2. 重要提示 PageHelper.startPage方法重要提示
只有紧跟在PageHelper.startPage方法后的第一个Mybatis的查询(Select)方法会被分页。
请不要配置多个分页插件