1,myibatis延迟加载
存在多表关联查询时,不需要一下子把全部表都拿出来的时候,可以采用延迟加载,先取出单表,等需要时再取出其他表,这样可以大幅提高数据库性能。
相关table可自行建立,目录结构如下:
(1)延迟加载测试方法:
// 延迟加载测试
@Test
public void testfindOrdersUserLazyLoad(){
SqlSession session = MybatisUtil.getSqlSession();
OrdersMapper mapper = session.getMapper(OrdersMapper.class);
List
for (Orders orders : list) {
System.out.println(orders.getUser());
}
}
(2)findOrdersUserLazyLoad相关的OrdersMapper.xml配置:
column="user_id" >
延迟加载配置的核心就在于association里的配置,property表示要将查询的结果注入到那个属性中,由于它是个集合,需要javaType表示集合里元素的类型,coLumn:指定关联查询的列 。
(3)设置总的配置文件的延迟加载属性
(4)结果展示
List
[DEBUG] - ==> Preparing: SELECT * FROM orders
[DEBUG] - ==> Parameters:
[DEBUG] - <== Total: 3
System.out.println(orders.getUser()); 到了这一步时,由于要调用user时,所以会去查找users,之后的循环没有发出sql:
[DEBUG] - ==> Preparing: select * from user where id = ?
[DEBUG] - ==> Parameters: 1(Integer)
[DEBUG] - <== Total: 1
[DEBUG] - ==> Preparing: select * from user where id = ?
[DEBUG] - ==> Parameters: 10(Integer)
[DEBUG] - <== Total: 1
每根据一个user_id进行一次查询是否效率很低?
(5)aggressiveLazyLoading属性
如果在setting中加入
当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。
这句话有点绕,实际效果如下说明:
List
[DEBUG] - ==> Preparing: SELECT * FROM orders
[DEBUG] - ==> Parameters:
[DEBUG] - <== Total: 3
for (Orders orders : list) { 到了这一步也没有发出sql
System.out.println(orders.getUser()); 在方法体里,每一次循环再发出一次sql(这种方式让延迟加载按需执行)
[DEBUG] - ==> Preparing: select * from user where id = ?
[DEBUG] - ==> Parameters: 1(Integer)
[DEBUG] - <== Total: 1
但是测试的时候发现aggressiveLazyLoading设为true和false发出的sql是一样的,发出sql顺序相同,没发现区别,对懒加载也没影响。可能是同时存在两个懒属性时,调用其中一个,是否会加载其他懒属性的一个区分。
2,mybaits提供一级缓存,和二级缓存。
一级缓存SqlSession级别的缓存,同一数据可以保存在同一个
二级缓存是mapper级别,多个SqlSession去操作同一个Mapper的sql语句,不用重复发送sql请求。
一级缓存比较简单,同一条sql,查了一次就不会重复查,不用配置,当其他语句更新了数据之后,通过commit更新后再查即可即可。
不过测试的过程很有意思,如下代码:
@Test
public void testFindUser(){
SqlSession session = MybatisUtil.getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
// SqlSession session2 = MybatisUtil.getSqlSession();
// UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user = mapper.findById(1);
// User user2 = mapper2.findById(1);
/*
* 执行了(更新,插入,删除),会自动清空sqlsession的一级缓存,
* 目的:为了避免脏读,保持缓存中数据是最新的
*/
User userrUser = new User();
userrUser.setId(1);
userrUser.setUsername("aaaaaaa");
mapper.updateUser(userrUser);
// 执行了更新,插入,删除操作后,需要执行 commit 提交
// session.commit();
User user1 = mapper.findById(1);
System.out.println(user);
System.out.println(user1);
session.close();
}
发现即使session没有commit,虽然只发出了一条sql,但是user1依然改变了username,很神奇。是不是说mybatis有一套机制避免脏读?
二级缓存同事在SqlMapConfig.xml和相关mapper.xml设置二级缓存即可。
SqlMapConfig.xml:
UserMapper.xml:
或者:
测试方法:
@Test
public void testErJiFindUser(){
SqlSession session = MybatisUtil.getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
SqlSession session2 = MybatisUtil.getSqlSession();
UserMapper mapper2 = session2.getMapper(UserMapper.class);
SqlSession session3 = MybatisUtil.getSqlSession();
UserMapper mapper3 = session3.getMapper(UserMapper.class);
User user = mapper.findById(1);
System.out.println(user.getUsername());
// 执行关闭以后,才会将数据缓存到二级缓存中
session.close();
User user2 = mapper2.findById(1);
System.out.println(user2.getUsername());
session2.close();
/*
* 执行了(更新,插入,删除),会自动清空sqlsession的一级缓存,
* 目的:为了避免脏读,保持缓存中数据是最新的
*/
// User userrUser = new User();
// userrUser.setId(1);
// userrUser.setUsername("aaaaaaa");
// int i = mapper3.updateUser(userrUser);
// System.out.println(i);
// // 执行了更新,插入,删除操作后,需要执行 commit 提交
// session3.commit();
//
}
没开启二级缓存,则会发出三条select语句。
开启二级缓存后
[DEBUG] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@223f3642]
[DEBUG] - ==> Preparing: select * from user where id = ?
[DEBUG] - ==> Parameters: 1(Integer)
[DEBUG] - <== Total: 1
王五
[DEBUG] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@223f3642]
[DEBUG] - Closing JDBC Connection [
可以看出,这时只发出了一条sql。这里启用二级缓存的xml生成了一个HashMap,总的配置文件为何也要配置二级缓存?估计是为了整体管理
在statement中设置useCache=false可以禁用当前select语句的二级缓存:
为避免脏读,一个方法是commit,一个是加入flushCache="true":
3,mybatis的逆向工程
mybatis的逆向工程是通过如下jar包实现的
在项目的classpath配置generatorConfig.xml 如下:
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
userId="root"
password="123456">
targetProject="d:\">
在测试类中输出如下:
package com.mybatis.test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
public class GeneratorSqlmap {
public void generator() throws Exception{
List
boolean overwrite = true;
//指定 逆向工程配置文件
File configFile = new File("d:/generatorConfig.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);
}
public static void main(String[] args) throws Exception {
try {
GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
即可在d盘生成逆向工程项目