数据库连接池
- 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>
<!--配置mybatis环境-->
<properties resource="db.properties"></properties>
<environments default="mysql">
<!--配置mysql环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC" />
<!--
配置数据源
type:
UNPOOLED: 不使用连接池的数据源,Mybatis会创建UNPooledDataSource实例
POOLED: 使用连接池的数据源,Mybatis会创建PooledDataSource实例
JNDI: 使用JNDI实现的数据源,Mybatis会从JNDI服务上查找DataSource实例,然后返回
-->
<dataSource type="POOLED">
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
</environment>
</environments>
</configuration>
- Mybatis中获取DataSource
MyBatis通过DataSourceFactory中的getDataSource()方法来创建数据源DataSource对象(工厂模式)
public interface DataSourceFactory {
void setProperties(Properties var1);
DataSource getDataSource();
}
- Mybatis中存放DataSource
MyBatis 创建了 DataSource 实例后,会将其放到 Configuration 对象内的 Environment 对象中, 供以后使用
XMLConfigBuilder.class
省略....
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
省略....
public class Configuration {
protected Environment environment;
省略....
}
public final class Environment {
private final String id;
private final TransactionFactory transactionFactory;
private final DataSource dataSource;
public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
if (id == null) {
throw new IllegalArgumentException("Parameter 'id' must not be null");
} else if (transactionFactory == null) {
throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
} else {
this.id = id;
if (dataSource == null) {
throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
} else {
this.transactionFactory = transactionFactory;
this.dataSource = dataSource;
}
}
}
public String getId() {
return this.id;
}
public TransactionFactory getTransactionFactory() {
return this.transactionFactory;
}
public DataSource getDataSource() {
return this.dataSource;
}
public static class Builder {
private String id;
private TransactionFactory transactionFactory;
private DataSource dataSource;
public Builder(String id) {
this.id = id;
}
public Environment.Builder transactionFactory(TransactionFactory transactionFactory) {
this.transactionFactory = transactionFactory;
return this;
}
public Environment.Builder dataSource(DataSource dataSource) {
this.dataSource = dataSource;
return this;
}
public String id() {
return this.id;
}
public Environment build() {
return new Environment(this.id, this.transactionFactory, this.dataSource);
}
}
}
- Mybatis中连接的获取过程分析
Stream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession sqlSession = factory.openSession();
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
//这个时候才会触发 MyBatis 在底层执行下面这个方法来创建 java.sql.Connection 对象(可以通过断点调试)
List<User> users = mapper.findAll();
事务控制
Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制
为什么必须使用 sqlSession.commit()提交事务?
主要原因就是在连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,这样我们就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit()方法实现事务提交。
Stream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//设置事务自动提交
SqlSession sqlSession = factory.openSession(true);
动态SQL语句
有些时候业务逻辑复杂时,我们的 SQL 是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了
- if
<?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.sn511.mybatis.dao.IUserDao">
<select id="findByUser" resultType="com.sn511.mybatis.domain.User" parameterType="com.sn511.mybatis.domain.User">
select * from user where 1=1
<if test="name!=null and name != '' ">
and name like #{name}
</if>
<if test="age != null">
and age = #{age}
</if>
</select>
</mapper>
@Test
public void test(){
User user = new User();
user.setName("%王%");
user.setAge(10);
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
List<User> users = mapper.findByUser(user);
System.out.println(users);
}
- where
<?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.sn511.mybatis.dao.IUserDao">
<select id="findByUser" resultType="com.sn511.mybatis.domain.User" parameterType="com.sn511.mybatis.domain.User">
select * from user
<where>
<if test="name!=null and name != '' ">
and name like #{name}
</if>
<if test="age != null">
and age = #{age}
</if>
</where>
</select>
</mapper>
- foreach
<?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.sn511.mybatis.dao.IUserDao">
<select id="findByUser" resultType="com.sn511.mybatis.domain.User" parameterType="com.sn511.mybatis.domain.User">
<!--
select * from user where id in (1,2,3)
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符
-->
select * from user
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
</mapper>
- 简化sql
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
<?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.sn511.mybatis.dao.IUserDao">
<sql id="defaultSql">
select * from user
</sql>
<select id="findByUser" resultType="com.sn511.mybatis.domain.User" parameterType="com.sn511.mybatis.domain.User">
<include refid="defaultSql"></include>
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
</mapper>
多表查询
- 一对一
# 实体类
# 用户
public class User {
private Integer id;
private String name;
private Integer age;
省略getter、setter、toString方法
}
# 账户, 一个用户有多个账户
public class Account {
private Integer id;
private Integer uid;
private Double money;
省略getter、setter、toString方法
}
# 为了能够封装查询结果, 定义一个新的实体类包含用户和账户的字段
public class AccountUser extends Account implements Serializable {
private String name;
private Integer age;
省略getter、setter方法
@Override
public String toString() {
return super.toString() + "AccountUser{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
# dao
public interface IAccountDao {
List<AccountUser> findAll();
}
# resources/com/sn511/mybatis/dao/IAccountDdao.xml
<?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.sn511.mybatis.dao.IAccountDao">
<select id="findAll" resultType="com.sn511.mybatis.domain.AccountUser">
select a.*,u.name,u.age from account a,user u where a.uid =u.id
</select>
</mapper>
# 测试
@Test
public void test1(){
IAccountDao mapper = sqlSession.getMapper(IAccountDao.class);
List<AccountUser> all = mapper.findAll();
for (AccountUser accountUser : all){
System.out.println(accountUser.toString());
}
}
- 一对多
public class User {
private Integer id;
private String name;
private Integer age;
List<Account> accounts;
省略getter、setter、toString方法
}
public interface IUserDao {
List<User> findAll();
}
<?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.sn511.mybatis.dao.IUserDao">
<!--
collection: 部分定义了用户关联的账户信息。表示关联查询结果集
ofType: 指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名
-->
<resultMap id="userMap" type="com.sn511.mybatis.domain.User">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="age" property="age"></result>
<collection property="accounts" ofType="com.sn511.mybatis.domain.Account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid, a.uid, a.money from user u left join account a on u.id = a.uid
</select>
</mapper>
@Test
public void test1(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
List<User> all = mapper.findAll();
System.out.println(all.toString());
}
- 多对多
延迟加载策略
实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的账户信息。此时就是我们所说的延迟加载。
延迟加载: 在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降
Mybatis缓存
像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。Mybatis 中缓存分为一级缓存,二级缓存。
- 一级缓存
一级缓存是SqlSession级别的缓存,只要SqlSession没有flush或close,它就存在。
public interface IUserDao {
User findById(Integer id);
}
<?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.sn511.mybatis.dao.IUserDao">
<select id="findById" parameterType="int" resultType="com.sn511.mybatis.domain.User">
select * from user where id = #{id}
</select>
</mapper>
@Test
public void test(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
User user1 = mapper.findById(1);
User user2 = mapper.findById(1);
System.out.println(user1); // com.sn511.mybatis.domain.User@186a70
System.out.println(user2); // com.sn511.mybatis.domain.User@186a70
System.out.println(user1 == user2); // true
}
分析:
1.第一次查询,先去缓存中查找,没有才去数据库查询,然后将查询的用户信息存到一级缓存中。
2.第二次查询,先去缓存中查找,有,就没有再进行数据库查询操作。
注: 如果sqlSession执行了commit操作,就会清空sqlSession中的一级缓存,这样就目的是为了让缓存中存在最新的信息,避免脏读。
- 二级缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
1.开启和关闭二级缓存
# SqlMapConfig.xml
<?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>
<!--配置mybatis环境-->
<properties resource="db.properties"></properties>
<settings>
<!--
开启二级缓存的支持
默认为true, true代表开启二级缓存, false代表关闭二级缓存
-->
<setting name="cacheEnabled" value="true"/>
<!-- 打印查询语句 -->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<environments default="mysql">
<!--配置mysql环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC" />
<!--
配置数据源
type:
UNPOOLED: 不使用连接池的数据源,Mybatis会创建UNPooledDataSource实例
POOLED: 使用连接池的数据源,Mybatis会创建PooledDataSource实例
JNDI: 使用JNDI实现的数据源,Mybatis会从JNDI服务上查找DataSource实例,然后返回
-->
<dataSource type="POOLED">
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
</environment>
</environments>
<!--mybatis映射配置的位置-->
<mappers>
<mapper resource="com/sn511/mybatis/dao/IUserDao.xml" />
</mappers>
</configuration>
# IUserDao.xml
<?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.sn511.mybatis.dao.IUserDao">
<!-- 开启二级缓存的支持, 区分的标准就看 mapper的namespace值 -->
<cache></cache>
<!--
设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false
-->
<select id="findById" parameterType="int" resultType="com.sn511.mybatis.domain.User" useCache="true">
select * from user where id = #{id}
</select>
</mapper>
# 测试
@Test
public void test(){
SqlSession sqlSession1 = factory.openSession();
IUserDao mapper1 = sqlSession1.getMapper(IUserDao.class);
User user1 = mapper1.findById(1);
System.out.println("user1:" + user1);
sqlSession1.close();//一级缓存消失
SqlSession sqlSession2 = factory.openSession();
IUserDao mapper2 = sqlSession2.getMapper(IUserDao.class);
User user2 = mapper2.findById(1);
System.out.println("user2:" + user2);
sqlSession2.close();
}
# 输出
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Cache Hit Ratio [com.sn511.mybatis.dao.IUserDao]: 0.0
Opening JDBC Connection
Created connection 1709567.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a15ff]
==> Preparing: select * from user where id = ?
==> Parameters: 1(Integer)
<== Columns: id, name, age
<== Row: 1, 张三, 11
<== Total: 1
user1:com.sn511.mybatis.domain.User@1ca2dfa
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a15ff]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a15ff]
Returned connection 1709567 to pool.
Cache Hit Ratio [com.sn511.mybatis.dao.IUserDao]: 0.5
user2:com.sn511.mybatis.domain.User@171c76a
结论:
第一次有数据库查询
第二次没有数据库查询,说明数据来自于二级缓存
# 注
使用二级缓存实体类一定要实现java.io.Serializable 接口
注解开发
- 基本的增删改查
# SqlMapConfig.xml
<?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 文件的位置-->
<properties resource="db.properties"></properties>
<!-- 配置别名的注册 -->
<typeAliases>
<package name="com.sn511.mybatis.domain"/>
</typeAliases>
<!-- mysql环境 -->
<environments default="mysql">
<!--配置mysql环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC" />
<!--
配置数据源
type:
UNPOOLED: 不使用连接池的数据源,Mybatis会创建UNPooledDataSource实例
POOLED: 使用连接池的数据源,Mybatis会创建PooledDataSource实例
JNDI: 使用JNDI实现的数据源,Mybatis会从JNDI服务上查找DataSource实例,然后返回
-->
<dataSource type="POOLED">
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
</environment>
</environments>
<!--配置映射信息-->
<mappers>
<!--
配置dao接口的位置
方式1: mapper标签配置class属性
方式2: package标签指定dao接口的包位置
-->
<package name="com.sn511.mybatis.dao"/>
</mappers>
</configuration>
public interface IUserDao {
/**
* 查询所有用户信息
*/
@Select("select * from user")
List<User> findAll();
/**
* 根据id查询用户信息
*/
@Select("select * from user where id = #{id}")
User fingById(Integer id);
/**
* 查询用户数量
*/
@Select("select count(*) from user")
int findTotal();
/**
* 根据姓名模糊查询用户信息
*/
@Select("select * from user where name like #{name} ")
List<User> findByName(String name);
/**
* 保存用户信息
*/
@Insert("insert into user (name, age) values (#{name}, #{age})")
int saveUser(User user);
/**
* 保存用户信息并返回用户信息id, 用户id在user中保存
*/
@Insert("insert into user (name, age) values (#{name}, #{age})")
@SelectKey(keyColumn = "id", keyProperty = "id", resultType = Integer.class, before = false, statement = {"select last_insert_id()"})
int saveUserGetId(User user);
/**
* 更新用户信息
*/
@Update("update user set name=#{name}, age=#{age} where id = #{id}")
int updateUser(User user);
/**
* 根据id删除用户信息
*/
@Delete("delete from user where id = #{id}")
int deleteUser(Integer id);
}
# 测试
public class TestUser {
InputStream in;
SqlSessionFactoryBuilder builder;
SqlSessionFactory factory;
SqlSession sqlSession;
@Before
public void init() throws Exception{
//读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//构建者
builder = new SqlSessionFactoryBuilder();
//SqlSession工厂
factory = builder.build(in);
sqlSession = factory.openSession();
}
@After
public void destroy() throws Exception{
sqlSession.commit();
sqlSession.close();
in.close();
}
@Test
public void testFindAll(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
List<User> all = mapper.findAll();
for(User user:all){
System.out.println(user.toString());
}
}
@Test
public void testFindById(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
User user = mapper.fingById(1);
System.out.println(user.toString());
}
@Test
public void testSaveUser(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setName("李四");
user.setAge(15);
int i = mapper.saveUser(user);
System.out.println(i);
}
@Test
public void testSaveUserGetId(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setName("王五");
user.setAge(16);
int i = mapper.saveUserGetId(user);
System.out.println(i);
System.out.println(user.getId()); //返回插入记录的主键ID
}
@Test
public void testUpdateUser(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setId(9);
user.setName("王小五");
user.setAge(17);
int i = mapper.updateUser(user);
System.out.println(i);
}
@Test
public void testDeleteUser(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
int i = mapper.deleteUser(9);
System.out.println(i);
}
@Test
public void testTotal(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
int i = mapper.findTotal();
System.out.println(i);
}
@Test
public void testFindByName(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
List<User> users = mapper.findByName("%五%");
System.out.println(users);
}
}
- 使用注解实现复杂关系映射开发
@Results 注解
代替的是标签<resultMap>
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})
@Results(@Result())
@Resutl 注解
代替了 <id>标签和<result>标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
- 一对一
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
}
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
private User user;
}
public interface IAccountDao {
@Select("select * from account")
@Results(id = "accountMap",
value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "id", property = "id"),
@Result(column = "uid", property = "uid"),
@Result(column = "money", property = "money"),
@Result(column = "uid", property = "user",
one = @One(select = "com.sn511.mybatis.dao.IUserDao.findById", fetchType = FetchType.LAZY))
})
List<Account> findAll();
}
public interface IUserDao {
/**
* 根据id查询用户信息
*/
@Select("select * from user where id = #{uid}")
User fingById(Integer id);
}
# 测试
@Test
public void testFindByName1(){
IAccountDao mapper = sqlSession.getMapper(IAccountDao.class);
List<Account> all = mapper.findAll();
System.out.println(all);
}
- 一对多
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private List<Account> accounts;
}
public class Account {
private Integer id;
private Integer uid;
private Double money;
}
public interface IAccountDao {
@Select("select * from account where uid = #{uid}")
List<Account> findByUid(Integer id);
}
public interface IUserDao {
/**
* 查询所有用户信息
*/
@Select("select * from user")
@Results(id = "userMap",
value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "age", property = "age"),
@Result(column = "id", property = "accounts",
many = @Many(
select = "com.sn511.mybatis.dao.IAccountDao.findByUid",
fetchType = FetchType.LAZY
))
})
List<User> findAll();
}
# 测试
@Test
public void test(){
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
List<User> all = mapper.findAll();
System.out.println(all);
}
- 基于注解方式的二级缓存
@CacheNamespace(blocking = true)
public interface IUserDao {
}
网友评论