一、mybatis 的常用注解说明
@Insert:
实现新增
@Update:
实现更新
@Delete:
实现删除
@Select:
实现查询
@Result:
实现结果集封装
@Results:
可以与
@Result
一起使用,封装多个结果集
@ResultMap:
实现引用
@Results
定义的封装
@One:
实现一对一结果集封装
@Many:
实现一对多结果集封装
@SelectProvider:
实现动态
SQL
映射
@CacheNamespace:
实现注解二级缓存的使用
二、使用 Mybatis 注解实现基本 CRUD
1.编写实体类
@Data
public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
}
注意:
此处我们故意和数据库表的列名不一致。
2.使用注解方式开发持久层接口
package cn.oesoft.mybatisannotation.dao;
import cn.oesoft.mybatisannotation.domain.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* @ClassName: IUserDao
* @Author: linxin
* @Date: 2021/6/16 11:37
* @Company: http://www.oesoft.cn
* @Description: TODO
*/
public interface IUserDao {
/**
* 查询所有用户
*
* @return
*/
@Select("select * from user")
@Results(id = "userMap",
value = {
@Result(id = true, column = "id", property = "userId"),
@Result(column = "username", property = "userName"),
@Result(column = "sex", property = "userSex"),
@Result(column = "address", property = "userAddress"),
@Result(column = "birthday", property = "userBirthday")
})
List<User> findAll();
/**
* 根据 id 查询一个用户
*
* @param userId
* @return
*/
@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);
/**
* 保存操作
*
* @param user
* @return
*/
@Insert("insert into user(username, sex, birthday, address) values(#{userName},#{userSex},#{userBirthday},#{userAddress})")
@SelectKey(keyColumn = "id", keyProperty = "userId", resultType = Integer.class, before =false, statement = {"select last_insert_id()"})
int saveUser(User user);
/**
* 更新操作
* @param user
* @return
*/
@Update("update user set username=#{userName}, address =#{userAddress}, sex =#{userSex}, birthday =#{userBirthday} " +
"where id=#{userId}")
int updateUser(User user);
/**
* 删除用户
*
* @param userId
* @return
*/
@Delete("delete from user where id = #{userId} ")
int deleteUser(Integer userId);
/**
* 查询使用聚合函数
*
* @return
*/
@Select("select count(*) from user ")
int findTotal();
/**
* 模糊查询
*
* @param name
* @return
*/
@Select("select * from user where username like #{username} ")
@ResultMap("userMap")
List<User> findByName(String name);
}
3.编写 SqlMapConfig 配置文件
<?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">
<!-- mybatis的主配置文件 -->
<configuration>
<!-- 配置 properties 文件的位置 -->
<properties resource="jdbcConfig.properties"></properties>
<!-- 配置别名的注册 -->
<typeAliases>
<package name="cn.oesoft.mybatisannotation.domain"/>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置 mysql 的环境 -->
<environment id="mysql">
<!-- 配置事务的类型是 JDBC -->
<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>
<!-- 配置映射信息 -->
<mappers>
<!-- 配置 dao 接口的位置,它有两种方式
第一种:使用 mapper 标签配置 class 属性
第二种:使用 package 标签,直接指定 dao 接口所在的包
-->
<package name="cn.oesoft.mybatisannotation.dao"/>
</mappers>
</configuration>
4.编写测试方法
import cn.oesoft.mybatisannotation.dao.IUserDao;
import cn.oesoft.mybatisannotation.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.sql.Date;
import java.util.List;
/**
* @ClassName: MybatisAnnotationCRUDTest
* @Author: linxin
* @Date: 2021/6/16 14:25
* @Company: http://www.oesoft.cn
* @Description: TODO
*/
public class MybatisAnnotationCRUDTest {
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
/**
* 测试查询一个
*/
@Test
public void testFindById() {
User user = userDao.findById(41);
System.out.println(user);
}
/**
* 测试保存
*/
@Test
public void testSave() {
User user = new User();
user.setUserName("mybatis annotation");
user.setUserSex("男");
user.setUserAddress("北京市顺义区");
user.setUserBirthday(new Date(System.currentTimeMillis()));
int res = userDao.saveUser(user);
System.out.println("影响数据库记录的行数:" + res);
System.out.println("插入的主键值:" + user.getUserId());
}
/**
* 测试更新
*/
@Test
public void testUpdate() {
User user = userDao.findById(63);
user.setUserBirthday(new Date(System.currentTimeMillis()));
user.setUserSex("女");
int res = userDao.updateUser(user);
System.out.println(res);
}
/**
* 测试删除
*/
@Test
public void testDelete() {
int res = userDao.deleteUser(63);
System.out.println(res);
}
/**
* 测试查询使用聚合函数
*/
@Test
public void testFindTotal() {
int res = userDao.findTotal();
System.out.println(res);
}
/**
* 测试模糊查询
*/
@Test
public void testFindByName() {
List<User> users = userDao.findByName("%m%");
for (User user : users) {
System.out.println(user);
}
}
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
@Before//junit 的注解
public void init() throws Exception {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);
//3.创建 session
session = factory.openSession();
//4.创建代理对象
userDao = session.getMapper(IUserDao.class);
}
@After//junit 的注解
public void destroy() throws Exception {
//提交事务
session.commit();
//释放资源
session.close();
//关闭流
in.close();
}
}
三、使用注解实现复杂关系映射开发
1.复杂关系映射的注解说明
@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=
""
))
2.使用注解实现一对一复杂关系映射及延迟加载
需求:
加载账户信息时并且加载该账户的用户信息,根据情况可实现延迟加载。(注解方式实现)
a.添加 Account 实体类
@Data
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//多对一关系映射:从表方应该包含一个主表方的对象引用
private User user;
}
b.添加账户的持久层接口并使用注解配置
public interface IAccountDao {
/**
* 查询所有账户,采用延迟加载的方式查询账户的所属用户
* @return
*/
@Select("select * from account")
@Results(id="accountMap",
value= {
@Result(id=true,column="id",property="id"),
@Result(column="uid",property="uid"),
@Result(column="money",property="money"),
@Result(column="uid",
property="user",
one=@One(select="cn.oesoft.mybatisannotation.dao.IUserDao.findById",
fetchType= FetchType.LAZY) )
})
List<Account> findAll();
}
c.添加用户的持久层接口并使用注解配置
public interface IUserDao {
/**
* 查询所有用户
*
* @return
*/
@Select("select * from user")
@Results(id = "userMap",
value = {
@Result(id = true, column = "id", property = "userId"),
@Result(column = "username", property = "userName"),
@Result(column = "sex", property = "userSex"),
@Result(column = "address", property = "userAddress"),
@Result(column = "birthday", property = "userBirthday")
})
List<User> findAll();
/**
* 根据 id 查询一个用户
*
* @param userId
* @return
*/
@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);
}
d.测试一对一关联及延迟加载
public class AccountTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IAccountDao accountDao;
@Before//junit 的注解
public void init() throws Exception {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);
//3.创建 session
session = factory.openSession();
//4.创建代理对象
accountDao = session.getMapper(IAccountDao.class);
}
@After//junit 的注解
public void destroy() throws Exception {
//提交事务
session.commit();
//释放资源
session.close();
//关闭流
in.close();
}
@Test
public void testFindAll() {
List<Account> accounts = accountDao.findAll();
for(Account account : accounts) {
System.out.println(account.getMoney());
//System.out.println(account.getUser());
}
}
}
3.使用注解实现一对多复杂关系映射
需求:
查询用户信息时,也要查询他的账户列表。使用注解方式实现。
分析:
一个用户具有多个账户信息,所以形成了用户
(User)
与账户
(Account)
之间的一对多关系。
a.User 实体类加入 List<Account>
//一对多关系映射:主表方应该包含一个从表方的集合引用
private List<Account> accounts;
b.编写用户的持久层接口并使用注解配置
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="address",property="userAddress"),
@Result(column="birthday",property="userBirthday"),
@Result(column="id",property="accounts",
many=@Many(
select="cn.oesoft.mybatisannotation.dao.IAccountDao.findByUid",
fetchType= FetchType.LAZY
) )
})
List<User> findAll();
@Many:
相当于
<collection>
的配置
select
属性:代表将要执行的
sql
语句
fetchType
属性:代表加载方式,一般如果要延迟加载都设置为
LAZY
的值
c.编写账户的持久层接口并使用注解配置
/**
* 根据用户 id 查询用户下的所有账户
* @param userId
* @return
*/
@Select("select * from account where uid = #{uid} ")
List<Account> findByUid(Integer userId);
d.添加测试方法
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println("-----每个用户的内容-----");
System.out.println(user.getUserName());
// System.out.println(user.getAccounts());
}
}
四、mybatis 基于注解的二级缓存
1.在 SqlMapConfig 中开启二级缓存支持
<!-- 配置二级缓存 -->
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
2.在持久层接口中使用注解配置二级缓存
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {
3.添加测试方法
/**
* 测试二级缓存
*/
@Test
public void testSecondLevelCache(){
SqlSession sqlSession1 = factory.openSession();
IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = dao1.findById(41);
System.out.println(user1);
sqlSession1.close();//一级缓存消失
SqlSession sqlSession2 = factory.openSession();
IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = dao2.findById(41);
System.out.println(user2);
sqlSession2.close();
System.out.println(user1 == user2);
}