Mybatis常用的注解开发CRUD&&复杂关系映射(一对一,一对多)&&mybatis 基于注解的二级缓存
程序员文章站
2022-07-12 22:37:23
...
Mybatis 注解开发
1.常用的注解说明
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
1.Mybatis常用的注解开发CRUD
Maven项目里面的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Mybatis_annotation</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>
</project>
项目概况:
不需要写映射配置
jdbcConfig.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/li
jdbc.username=root
jdbc.password=517818li
1.1设置实体类User
故意设置于=与数据库列名不一致
package Annotation.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable{
private Integer userId;
private String userName;
private Date userBirthDay;
private String userSex;
private String userAddress;
@Override
public String toString() {
return "User[" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userBirthDay=" + userBirthDay +
", userSex='" + userSex + '\'' +
", userAddress='" + userAddress + '\'' +
']';
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getUserBirthDay() {
return userBirthDay;
}
public void setUserBirthDay(Date userBirthDay) {
this.userBirthDay = userBirthDay;
}
public String getUserSex() {
return userSex;
}
public void setUserSex(String userSex) {
this.userSex = userSex;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
}
1.2配置用户接口IUserDao
需要注意的是: @Update("update user set username=#{userName},sex=#{userSex},address = #{userAddress},birthday = #{userBirthDay} where id = #{userId} ")
#{…}里面的要与实体类定义的列名对应
package Annotation.dao;
import Annotation.domain.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface IUserDao {
/**1. 查询操作**/
@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();
/**2.根据id查询用户*/
@Select("select * from user where id = #{uid}")
@ResultMap("userMap")
User findById(Integer uid);
/**3.保存操作
*
*/
@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);
/**
* 4.更新操作
*/
@Update("update user set username=#{userName},sex=#{userSex},address = #{userAddress},birthday = #{userBirthDay} where id = #{userId} ")
int updateUser(User user);
/**
* 5.删除操作
*/
@Delete("delete from user where id = #{uid}")
int deleteUser(Integer userId);
/**
* 6.使用聚合函数查询
*/
@Select("select count(*) from user")
int findTotal();
/**
* 7.模糊查询
*/
@Select("select * from user where username like #{username} ")
@ResultMap("userMap")
List<User> findByName(String name);
}
1.3SqlMapConfig.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="jdbcConfig.properties"></properties>
<!-- 配置别名的注册 -->
<typeAliases>
<package name="Annotation.domain.User"/>
</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="Annotation.dao"/>
</mappers>
</configuration>
1.4测试类
import Annotation.dao.IUserDao;
import Annotation.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.util.Date;
import java.util.List;
public class AnnotationTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
/**
* 测试查询所有
*/
@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());
int res = userDao.saveUser(user);
System.out.println("影响数据库记录的行数:"+res);
System.out.println("插入的主键值:"+user.getUserId());
}
/**
* 测试更新
*/
@Test
public void testUpdate() {
User user = userDao.findById(43);
user.setUserBirthDay(new Date());
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("%王%");
for (User user : users) {
System.out.println(user);
}
}
@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();
}
}
2.使用注解实现复杂关系映射开发
实现复杂关系映射之前我们可以在映射文件中通过配置来实现
在使用注解开发时我们需要借助 @Results 注解, @Result 注解, @One 注解, @Many 注解。
2.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.2 使用注解实现一对一复杂关系映射及延迟加载
需求:
加载账户信息时并且加载该账户的用户信息,根据情况可实现延迟加载。(注解方式实现)
2.2.1Account账户实体类
package Annotation.domain;
public class Account {
private Integer id;
private Integer uid;
private Double money;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account[" +
"id=" + id +
", uid=" + uid +
", money=" + money +
']';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
2.2.2IAccountDao的接口
package Annotation.dao;
import Annotation.domain.Account;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
public interface IAccountDao{
@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="Annotation.dao.IUserDao.findById",
fetchType= FetchType.LAZY) )
})
List<Account> findAll();
}
2.2.3添加测试方法
private IAccountDao accountDao;
@Test
public void testFindAl(){
accountDao = session.getMapper(IAccountDao.class);
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println(account);
System.out.println(account.getUser());
}
}
2.2.4测试结果
2.3使用注解实现一对多复杂关系映射
2.3.1将Account加入User中
package Annotation.domain;
public class Account {
private Integer id;
private Integer uid;
private Double money;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account[" +
"id=" + id +
", uid=" + uid +
", money=" + money +
']';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
2.3.2在IAccountDao接口中加入
@Select("select * from account where uid = #{id}")
@ResultMap("accountMap")
List<Account> findByUid(Integer id);
2.3.3在IUserDao中修改Results
many = @Many(select =“Annotation.dao.IAccountDao.findByUid”)多对多
@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 ="Annotation.dao.IAccountDao.findByUid"))
})
2.3.4加入测试方法(一个用户能对应多个账户)
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println("用户信息");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
2.3.5查询结果
3 mybatis 基于注解的二级缓存
3…1 在 SqlMapConfig 中开启二级缓存支持
<!-- 配置二级缓存 --> <settings>
<!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/>
</settings>
3.2 在持久层接口中使用注解配置二级缓存
/**
*
* <p>Title: IUserDao</p>
* <p>Description: 用户的持久层接口</p>
* <p>Company: http://www.itheima.com/ </p>
*/
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}