MyBatis(十四)mybatis的注解开发

ゝ一纸荒年。 2021-06-22 15:37 635阅读 0赞

目录

  • Mybatis的注解开发
    • 一、注解开发的环境搭建
        1. 创建一个新的项目
        1. 导入坐标
        1. 实体类User
        1. dao接口
        1. log4j的配置文件
        1. jdbcConfig.properties
        1. SqlMapConfig.xml文件
        1. 给`findAll()`方法添加注解
        1. 测试类测试
      • · 注意事项
    • 二、单表CRUD操作(代理Dao方式)
        1. 常用注解说明
        1. 保存用户的操作
        1. 更新用户的操作
        1. 删除用户
        1. 根据id查询用户信息
        1. 根据用户名称进行模糊查询
        1. 查询用户数量
        1. 用注解建立实体类和数据库列名的关系
    • 三、复杂关系映射开发、多表操作
        1. 复杂关系映射的注解说明
        • **`@Results`** 注解
        • `@Resutl` 注解
        • `@One`注解(一对一)
        • `@Many`注解(多对一)
        1. 实现一对一复杂关系映射及延迟加载
        • ① **User实体类 和 Account实体类**
        • ② 持久层接口(使用注解配置)
        • ③ 测试类
        1. 一对多的复杂关系映射
        • ① `User`实体类中加入`List`
        • ② 持久层接口配置
        • ③ 测试方法:
    • 四、缓存的配置
        1. 在SqlMapConfig.xml中开启二级缓存支持
        1. 在持久层接口中使用注解配置二级缓存
        1. 测试方法

Mybatis的注解开发

一、注解开发的环境搭建

1. 创建一个新的项目

在这里插入图片描述

2. 导入坐标

pom.xml文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.veeja</groupId>
  5. <artifactId>day04_03mybatis</artifactId>
  6. <version>1.0-SNAPSHOT</version>
  7. <packaging>jar</packaging>
  8. <dependencies>
  9. <dependency>
  10. <groupId>org.mybatis</groupId>
  11. <artifactId>mybatis</artifactId>
  12. <version>3.4.5</version>
  13. </dependency>
  14. <dependency>
  15. <groupId>mysql</groupId>
  16. <artifactId>mysql-connector-java</artifactId>
  17. <version>5.1.6</version>
  18. </dependency>
  19. <dependency>
  20. <groupId>log4j</groupId>
  21. <artifactId>log4j</artifactId>
  22. <version>1.2.12</version>
  23. </dependency>
  24. <dependency>
  25. <groupId>junit</groupId>
  26. <artifactId>junit</artifactId>
  27. <version>4.10</version>
  28. </dependency>
  29. </dependencies>
  30. </project>

3. 实体类User

  1. package com.veeja.domain;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. public class User implements Serializable {
  5. private Integer id;
  6. private String username;
  7. private String address;
  8. private String sex;
  9. private Date birthday;
  10. @Override
  11. public String toString() {
  12. return "User{" +
  13. "id=" + id +
  14. ", username='" + username + '\'' +
  15. ", address='" + address + '\'' +
  16. ", sex='" + sex + '\'' +
  17. ", birthday=" + birthday +
  18. '}';
  19. }
  20. public Integer getId() {
  21. return id;
  22. }
  23. public void setId(Integer id) {
  24. this.id = id;
  25. }
  26. public String getUsername() {
  27. return username;
  28. }
  29. public void setUsername(String username) {
  30. this.username = username;
  31. }
  32. public String getAddress() {
  33. return address;
  34. }
  35. public void setAddress(String address) {
  36. this.address = address;
  37. }
  38. public String getSex() {
  39. return sex;
  40. }
  41. public void setSex(String sex) {
  42. this.sex = sex;
  43. }
  44. public Date getBirthday() {
  45. return birthday;
  46. }
  47. public void setBirthday(Date birthday) {
  48. this.birthday = birthday;
  49. }
  50. }

4. dao接口

  1. package com.veeja.dao;
  2. import com.veeja.domain.User;
  3. import java.util.List;
  4. /** * IUserDao接口 */
  5. public interface IUserDao {
  6. /** * 查询所有用户信息 * * @return */
  7. List<User> findAll();
  8. }

5. log4j的配置文件

src/main/resources下的log4j.properties:

  1. # Set root category priority to INFO and its only appender to CONSOLE.
  2. #log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
  3. log4j.rootCategory=debug, CONSOLE, LOGFILE
  4. # Set the enterprise logger category to FATAL and its only appender to CONSOLE.
  5. log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
  6. # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
  7. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
  8. log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
  9. log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
  10. # LOGFILE is set to be a File appender using a PatternLayout.
  11. log4j.appender.LOGFILE=org.apache.log4j.FileAppender
  12. log4j.appender.LOGFILE.File=d:\axis.log
  13. log4j.appender.LOGFILE.Append=true
  14. log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
  15. log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

6. jdbcConfig.properties

src/main/resources下的jdbcConfig.properties:

  1. jdbc.driver=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/mybatisdatabase
  3. jdbc.username=root
  4. jdbc.password=0000

7. SqlMapConfig.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
  3. <configuration>
  4. <!--引入外部配置文件-->
  5. <properties resource="jdbcConfig.properties"></properties>
  6. <!--配置别名-->
  7. <typeAliases>
  8. <package name="com.veeja.domain"/>
  9. </typeAliases>
  10. <!--配置环境-->
  11. <environments default="mysql">
  12. <environment id="mysql">
  13. <transactionManager type="JDBC"></transactionManager>
  14. <dataSource type="POOLED">
  15. <property name="driver" value="${jdbc.driver}"/>
  16. <property name="url" value="${jdbc.url}"/>
  17. <property name="username" value="${jdbc.username}"/>
  18. <property name="password" value="${jdbc.password}"/>
  19. </dataSource>
  20. </environment>
  21. </environments>
  22. <!--引入带有注解的dao接口所在位置-->
  23. <mappers>
  24. <package name="com.veeja.dao"/>
  25. </mappers>
  26. </configuration>

这样我们的环境就算搭建完成了。接下来我们就要尝试使用注解的方式进行开发了。

8. 给findAll()方法添加注解

  1. /** * 查询所有用户信息 * * @return */
  2. @Select("select * from user")
  3. List<User> findAll();

9. 测试类测试

  1. package com.veeja.test;
  2. import com.veeja.dao.IUserDao;
  3. import com.veeja.domain.User;
  4. import org.apache.ibatis.io.Resources;
  5. import org.apache.ibatis.session.SqlSession;
  6. import org.apache.ibatis.session.SqlSessionFactory;
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. import java.util.List;
  11. public class UserTest {
  12. /** * 测试基于注解的mybatis的使用 * * @param args */
  13. public static void main(String[] args) throws IOException {
  14. //1.获取字节输入流
  15. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  16. //2.根据字节输入流构建SqlSessionFactory
  17. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  18. //3.根据SqlSessionFactory生产一个SqlSeesion
  19. SqlSession session = factory.openSession();
  20. //4.使用sqlSession获取dao的代理对象
  21. IUserDao userDao = session.getMapper(IUserDao.class);
  22. //5.执行dao的方法
  23. List<User> users = userDao.findAll();
  24. for (User user : users) {
  25. System.out.println(user);
  26. }
  27. //6.释放资源
  28. session.close();
  29. in.close();
  30. }
  31. }

执行一下,完全没有问题:
在这里插入图片描述
这样我们的环境就算是搭建成功了!

· 注意事项

我们要额外注意一点,如果我们在使用注解的同时配置了xml映射文件,我们再次运行测试类,就会报错:
在这里插入图片描述

二、单表CRUD操作(代理Dao方式)

1. 常用注解说明

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与
@Result 一起使用,封装多个结果集
@ResultMap:实现引用
@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用

2. 保存用户的操作

IUserDao:

  1. /** * 添加用户 * * @param user */
  2. @Insert("insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})")
  3. void saveUser(User user);

测试:

  1. public class AnnotationCRUDTest {
  2. private InputStream in;
  3. private SqlSessionFactory factory;
  4. private SqlSession session;
  5. private IUserDao userDao;
  6. @Before
  7. public void init() throws IOException {
  8. in = Resources.getResourceAsStream("SqlMapConfig.xml");
  9. factory = new SqlSessionFactoryBuilder().build(in);
  10. session = factory.openSession();
  11. userDao = session.getMapper(IUserDao.class);
  12. }
  13. @After
  14. public void destroy() throws IOException {
  15. session.commit();
  16. session.close();
  17. in.close();
  18. }
  19. /** * 测试查询所有用户的信息 */
  20. @Test
  21. public void testFindAll() {
  22. List<User> users = userDao.findAll();
  23. for (User user : users) {
  24. System.out.println(user);
  25. }
  26. }
  27. /** * 测试:添加用户 */
  28. @Test
  29. public void testAddUser() {
  30. User user = new User();
  31. user.setUsername("新用户");
  32. user.setBirthday(new Date());
  33. user.setSex("男");
  34. user.setAddress("珠穆朗玛峰");
  35. userDao.saveUser(user);
  36. testFindAll();
  37. }
  38. }

结果:
在这里插入图片描述

3. 更新用户的操作

IUserDao:

  1. /** * 根据id更新用户的信息 * * @param user */
  2. @Update("update user " +
  3. "set username=#{username},sex=#{sex},address=#{address},birthday=#{birthday} " +
  4. "where id=#{id}")
  5. void updateUser(User user);

测试方法:

  1. /** * 测试:添加用户 */
  2. @Test
  3. public void testUpdateUser() {
  4. User user = new User();
  5. user.setUsername("超级新用户");
  6. user.setBirthday(new Date());
  7. user.setSex("男");
  8. user.setAddress("不是珠穆朗玛峰");
  9. user.setId(75);
  10. userDao.updateUser(user);
  11. testFindAll();
  12. }

测试结果:
在这里插入图片描述

4. 删除用户

IUserDao:

  1. /** * 删除用户 * * @param id */
  2. @Delete("delete from user where id=#{id}")
  3. void deleteUserByid(Integer id);

测试方法:

  1. /** * 测试删除用户 */
  2. @Test
  3. public void testDeleteUser() {
  4. userDao.deleteUserByid(75);
  5. testFindAll();
  6. }

结果:
在这里插入图片描述

5. 根据id查询用户信息

IUserDao:

  1. /** * 根据用户id查询用户信息 * * @param id * @return */
  2. @Select("select * from user where id=#{id}")
  3. User findUserById(Integer id);

测试方法:

  1. /** * 根据用户id查询用户信息 */
  2. @Test
  3. public void testFindUserById() {
  4. User user = userDao.findUserById(41);
  5. System.out.println(user);
  6. }

结果:
在这里插入图片描述

6. 根据用户名称进行模糊查询

IUserDao:

  1. /** * 根据用户名查询用户信息 * * @param username * @return */
  2. @Select("select * from user where username like #{username}")
  3. List<User> findUserByUsername(String username);

测试方法:

  1. /** * 测试:根据用户名查询用户信息 */
  2. @Test
  3. public void testFindUserByUsername() {
  4. List<User> users = userDao.findUserByUsername("%刘%");
  5. for (User user : users) {
  6. System.out.println(user);
  7. }
  8. }

或者使用:
在这里插入图片描述
结果:
在这里插入图片描述

7. 查询用户数量

IUserDao:

  1. /** * 查询总用户数量 * * @return */
  2. @Select("select count(*) from user")
  3. int findTotal();

测试方法:

  1. /** * 测试:查询用户数量 */
  2. @Test
  3. public void testFindTotal() {
  4. int count = userDao.findTotal();
  5. System.out.println(count);
  6. }

结果:
在这里插入图片描述

8. 用注解建立实体类和数据库列名的关系

如果我们的实体类中的属性名和数据库中的列名不相同的话,那么我们要进行额外的配置。
在这里插入图片描述
例如查询所有的操作:

  1. /** * 查询所有用户信息 * * @return */
  2. @Select("select * from user")
  3. @Results(id = "userMap", value = {
  4. @Result(id = true, column = "id", property = "userId"),
  5. @Result(column = "username", property = "userName"),
  6. @Result(column = "sex", property = "userSex"),
  7. @Result(column = "address", property = "userAddress"),
  8. @Result(column = "birthday", property = "userBirthday")
  9. })
  10. List<User> findAll();

而且我们在上面指定了Results的id,那么在下面其他的方法中就可以不用再定义一遍了,可以直接引用它的id就行了。
即:

  1. /** * 根据用户名查询用户信息 * * @param username * @return */
  2. @Select("select * from user where username like '%${value}%' ")
  3. @ResultMap(value = "userMap")
  4. List<User> findUserByUsername(String username);

三、复杂关系映射开发、多表操作

实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,在使用注解开发时我们需要借助@Results 注解,@Result 注解,@One 注解,@Many 注解。

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. 实现一对一复杂关系映射及延迟加载

需求:
加载账户信息时并且加载该账户的用户信息,根据情况可实现延迟加载。

User实体类 和 Account实体类

  1. package com.veeja.domain;
  2. public class User implements Serializable {
  3. private Integer userId;
  4. private String userName;
  5. private String userAddress;
  6. private String userSex;
  7. private Date userBirthday;
  8. @Override
  9. public String toString() {
  10. return "User{" +
  11. "userId=" + userId +
  12. ", userName='" + userName + '\'' +
  13. ", userAddress='" + userAddress + '\'' +
  14. ", userSex='" + userSex + '\'' +
  15. ", userBirthday=" + userBirthday +
  16. '}';
  17. }
  18. public Integer getUserId() {
  19. return userId;
  20. }
  21. public void setUserId(Integer userId) {
  22. this.userId = userId;
  23. }
  24. ......
  25. }
  26. package com.veeja.domain;
  27. import java.util.List;
  28. /** * @author veeja */
  29. public class Account {
  30. private Integer id;
  31. private Integer uid;
  32. private Double money;
  33. // 多对一(mybatis中称之为一对一)的对应关系
  34. private User user;
  35. @Override
  36. public String toString() {
  37. return "Account{" +
  38. "id=" + id +
  39. ", uid=" + uid +
  40. ", money=" + money +
  41. ", user=" + user +
  42. '}';
  43. }
  44. public Integer getId() {
  45. return id;
  46. }
  47. public void setId(Integer id) {
  48. this.id = id;
  49. }
  50. public Integer getUid() {
  51. return uid;
  52. }
  53. public void setUid(Integer uid) {
  54. this.uid = uid;
  55. }
  56. public Double getMoney() {
  57. return money;
  58. }
  59. public void setMoney(Double money) {
  60. this.money = money;
  61. }
  62. public User getUser() {
  63. return user;
  64. }
  65. public void setUser(User user) {
  66. this.user = user;
  67. }
  68. }

② 持久层接口(使用注解配置)

IAccountDao:

  1. /** * 查找所有的账户信息,并且获取每个用户所属的用户的信息 * * @return */
  2. @Select("select * from account")
  3. @Results(id = "accountMap", value = {
  4. @Result(id = true, column = "id", property = "id"),
  5. @Result(column = "uid", property = "uid"),
  6. @Result(column = "money", property = "money"),
  7. @Result(property = "user",
  8. column = "uid",
  9. one = @One(
  10. select = "com.veeja.dao.IUserDao.findUserById",
  11. fetchType = FetchType.EAGER))
  12. })
  13. List<Account> findAll();

IUserDao:

  1. /** * IUserDao接口 */
  2. public interface IUserDao {
  3. /** * 查询所有用户信息 * * @return */
  4. @Select("select * from user")
  5. @Results(id = "userMap",value = {
  6. @Result(id = true, column = "id", property = "userId"),
  7. @Result(column = "username", property = "userName"),
  8. @Result(column = "sex", property = "userSex"),
  9. @Result(column = "address", property = "userAddress"),
  10. @Result(column = "birthday", property = "userBirthday")
  11. })
  12. List<User> findAll();
  13. /** * 根据用户id查询用户信息 * * @param id * @return */
  14. @Select("select * from user where id=#{id}")
  15. @ResultMap(value = "userMap")
  16. User findUserById(Integer id);
  17. }

③ 测试类

  1. /** * 测试:查询所有用户信息 */
  2. @Test
  3. public void testFindAll() {
  4. List<Account> accounts = accountDao.findAll();
  5. for (Account account : accounts) {
  6. System.out.println(account);
  7. }
  8. }

结果:
在这里插入图片描述

3. 一对多的复杂关系映射

需求:
查询用户信息时,也要查询他的账户列表。

User实体类中加入List<Account>

  1. public class User implements Serializable {
  2. private Integer userId;
  3. private String userName;
  4. private String userAddress;
  5. private String userSex;
  6. private Date userBirthday;
  7. List<Account> accounts;
  8. public List<Account> getAccounts() {
  9. return accounts;
  10. }
  11. public void setAccounts(List<Account> accounts) {
  12. this.accounts = accounts;
  13. }
  14. ......
  15. }

② 持久层接口配置

IUserDao:

  1. /** * IUserDao接口 */
  2. public interface IUserDao {
  3. /** * 查询所有用户信息 * * @return */
  4. @Select("select * from user")
  5. @Results(id = "userMap", value = {
  6. @Result(id = true, column = "id", property = "userId"),
  7. @Result(column = "username", property = "userName"),
  8. @Result(column = "sex", property = "userSex"),
  9. @Result(column = "address", property = "userAddress"),
  10. @Result(column = "birthday", property = "userBirthday"),
  11. @Result(property = "accounts",
  12. column = "id",
  13. many = @Many(
  14. select = "com.veeja.dao.IAccountDao.findAccountsByUid",
  15. fetchType = FetchType.LAZY
  16. ))
  17. })
  18. List<User> findAll();
  19. /** * 根据用户id查询用户信息 * * @param id * @return */
  20. @Select("select * from user where id=#{id}")
  21. @ResultMap(value = "userMap")
  22. User findUserById(Integer id);
  23. }

IAccountDao:

  1. public interface IAccountDao {
  2. /** * 查找所有的账户信息,并且获取每个用户所属的用户的信息 * * @return */
  3. @Select("select * from account")
  4. @Results(id = "accountMap", value = {
  5. @Result(id = true, column = "id", property = "id"),
  6. @Result(column = "uid", property = "uid"),
  7. @Result(column = "money", property = "money"),
  8. @Result(property = "user",
  9. column = "uid",
  10. one = @One(
  11. select = "com.veeja.dao.IUserDao.findUserById",
  12. fetchType = FetchType.EAGER))
  13. })
  14. List<Account> findAll();
  15. /** * 根据用户id查询用户的账号信息 * * @return */
  16. @Select("select * from account where uid=#{uid}")
  17. List<Account> findAccountsByUid(Integer uid);
  18. }

③ 测试方法:

  1. /** * 测试:查询所有用户信息 */
  2. @Test
  3. public void testFindAll() {
  4. List<User> users = userDao.findAll();
  5. for (User user : users) {
  6. System.out.println(user);
  7. System.out.println(user.getAccounts());
  8. }
  9. }

结果:
在这里插入图片描述

四、缓存的配置

1. 在SqlMapConfig.xml中开启二级缓存支持

  1. <settings>
  2. <setting name="cacheEnabled" value="true"/>
  3. </settings>

2. 在持久层接口中使用注解配置二级缓存

  1. /** * IUserDao接口 */
  2. @CacheNamespace(blocking = true)
  3. public interface IUserDao {
  4. ......
  5. }

3. 测试方法

  1. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  2. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  3. //使用第一个session操作
  4. SqlSession session = factory.openSession();
  5. IUserDao userDao = session.getMapper(IUserDao.class);
  6. User user = userDao.findUserById(41);
  7. System.out.println(user);
  8. System.out.println(user.getAccounts());
  9. session.close();
  10. // 使用第二个session操作
  11. SqlSession session2 = factory.openSession();
  12. IUserDao userDao2 = session2.getMapper(IUserDao.class);
  13. User user2 = userDao2.findUserById(41);
  14. System.out.println(user2);
  15. System.out.println(user2.getAccounts());
  16. session2.close();
  17. in.close();

结果,我们是可以看到,只进行了一次查询的:
在这里插入图片描述


end.
mybatis的系列算是结束了,基础知识基本上都总结了。

发表评论

表情:
评论列表 (有 0 条评论,635人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Mybatis 注解开发

    这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射 文件了。本次我们先围绕一些基本的 CRUD 来学习,再学习复杂映