MyBatis 注解开发

文章源码

环境搭建

Mybatis 也可以使用注解开发方式,这样就可以减少编写 Mapper 映射文件。

常用注解说明:

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

单表 CRUD

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

  • @Results 代替了 <id> 标签和 <result> 标签,属性介绍:

    • id 是否是主键字段
    • column 数据库的列名
    • property 需要装配的属性名
    • one 需要使用的 @One 注解 @Result(one=@One)()
    • many 需要使用的 @Many 注解(@Result(many=@Many)()
  • @One(一对一) 代替了 <assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象,属性介绍:

    • select 指定用来多表查询的 sqlmapper
    • fetchType 会覆盖全局的配置参数 lazyLoadingEnabled
    • 使用格式:@Result(column=" ", property="", one=@One(select=""))
  • @Many(多对一)代替了 <collection> 标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合,

    • 使用格式:@Result(property="", column="", many=@Many(select=""))
  • 编写实体类

    public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    }
  • 使用注解方式开发持久层接口

    package cn.parzulpan.dao;
    
    import cn.parzulpan.domain.User;
    import org.apache.ibatis.annotations.*; import java.util.List; /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc : 用户的持久层接口,使用注解开发
    */ public interface UserDAO { /**
    * 查询所有用户
    * @return
    */
    @Select("select * from user")
    @Results(id = "userMap",
    value = {
    @Result(id = true, column = "id", property = "userId"),
    @Result(column = "username", property = "userName"),
    @Result(column = "birthday", property = "userBirthday"),
    @Result(column = "sex", property = "userSex"),
    @Result(column = "address", property = "userAddress")
    })
    List<User> findAll(); /**
    * 根据 id 查询一个用户
    * @param userId
    * @return
    */
    @Select("select * from user where id = #{uid}")
    @ResultMap(value = {"userMap"})
    User findById(Integer userId); /**
    * 插入操作
    * @param user
    * @return
    */
    @Insert("insert into user(username, birthday, sex, address) values (#{userName}, #{userBirthday}, #{userSex}, #{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}, birthday = #{userBirthday}, sex = #{userSex}, " +
    "address = #{userAddress} where id = #{userId}")
    int updateUser(User user); /**
    * 删除操作
    * @param userId
    * @return
    */
    @Delete("delete from user where id = #{uid}")
    int deleteUser(Integer userId); /**
    * 使用聚合函数查询
    * @return
    */
    @Select("select count(*) from user")
    int findTotal(); /**
    *
    * @param name
    * @return
    */
    @Select("select * from user where username like #{username}")
    @ResultMap(value = {"userMap"})
    List<User> findByName(String name); }
  • 编写 SqlMapConfig 配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mabatis.org//DTD Congfig 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration>
    <!-- 配置 properties 文件的位置 -->
    <properties resource="JDBCConfig.properties"/> <!-- 配置别名 -->
    <typeAliases>
    <package name="cn.parzulpan.domain"/>
    </typeAliases> <!-- 配置 MySQL 环境 -->
    <environments default="mysql">
    <environment id="mysql">
    <transactionManager type="JDBC"/>
    <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>
    <package name="cn.parzulpan.dao"/>
    </mappers>
    </configuration>
  • 编写测试方法

    package cn.parzulpan;
    
    import cn.parzulpan.dao.UserDAO;
    import cn.parzulpan.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; /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc :
    */ public class MyBatisAnnotationCRUDTest {
    private InputStream is;
    private SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    private UserDAO userDAO; @Before
    public void init() throws Exception {
    System.out.println("Before...");
    is = Resources.getResourceAsStream("SqlMapConfig.xml");
    sqlSessionFactory = builder.build(is);
    sqlSession = sqlSessionFactory.openSession();
    userDAO = sqlSession.getMapper(UserDAO.class);
    } @After
    public void destroy() throws Exception {
    System.out.println("After...");
    sqlSession.commit();
    sqlSession.close();
    is.close();
    } @Test
    public void findAllTest() {
    List<User> users = userDAO.findAll();
    for (User user : users) {
    System.out.println(user);
    }
    } @Test
    public void findByIdTest() {
    User user = userDAO.findById(41);
    System.out.println(user);
    } @Test
    public void saveUserTest() {
    User user = new User(null, "annotation username", new Date(), "男", "Beijing");
    System.out.println("save before: " + user); // User{id=null, ...}
    int i = userDAO.saveUser(user);
    System.out.println(i);
    System.out.println("save after: " + user); // User{id=53, ...}
    } @Test
    public void updateUserTest() {
    User user = userDAO.findById(42);
    user.setUserName("Tom Tim Tom AA");
    user.setUserAddress("瑞典");
    int i = userDAO.updateUser(user);
    System.out.println(i);
    } @Test
    public void deleteUserTest() {
    int i = userDAO.deleteUser(53);
    System.out.println(i);
    } @Test
    public void findTotalTest() {
    int total = userDAO.findTotal();
    System.out.println(total);
    } @Test
    public void findByNameTest() {
    List<User> users = userDAO.findByName("%Tim%");
    for (User user : users) {
    System.out.println(user);
    }
    }
    }

多表查询

一对一

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

  • 添加 User 实体类及 Account 实体类

    public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money; private User user; // 一对一
    }
  • 添加账户的持久层接口并使用注解配置

    package cn.parzulpan.dao;
    
    import cn.parzulpan.domain.Account;
    import org.apache.ibatis.annotations.One;
    import org.apache.ibatis.annotations.Result;
    import org.apache.ibatis.annotations.Results;
    import org.apache.ibatis.annotations.Select;
    import org.apache.ibatis.mapping.FetchType; import java.util.List; /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc :
    */ public interface AccountDAO { /**
    * 查询所有账户,采用延迟加载的方式查询账户的所属用户
    * @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.parzulpan.dao.UserDAO.findById", fetchType = FetchType.LAZY))
    })
    List<Account> findAll();
    }
  • 测试一对一关联及延迟加载

    @Test
    public void findAllTest() {
    List<Account> accounts = accountDAO.findAll();
    for (Account account : accounts) {
    System.out.println();
    System.out.println(account);
    System.out.println(account.getUser());
    }
    }
    ``

一对多

需求:查询用户信息时,也要查询他的账户列表。使用注解方式实现。

  • User 实体类加入 List<Account>

    public class User implements Serializable {
    private Integer userId; // 注意这里的和数据库表的列名不一致
    private String userName;
    private Date userBirthday;
    private String userSex;
    private String userAddress; private List<Account> accounts; //一对多关系映射:主表方法应该包含一个从表方的集合引用
    }
  • 编写用户的持久层接口并使用注解配置

    public interface UserDAO {
    /**
    * 查询所有用户,包括账户列表
    * @return
    */
    @Select("select * from user")
    @Results(id = "userMapWithAccount",
    value = {
    @Result(id = true, column = "id", property = "userId"),
    @Result(column = "username", property = "userName"),
    @Result(column = "birthday", property = "userBirthday"),
    @Result(column = "sex", property = "userSex"),
    @Result(column = "address", property = "userAddress"),
    @Result(column = "id", property = "accounts", many = @Many(
    select = "cn.parzulpan.dao.AccountDAO.findByUid",
    fetchType = FetchType.LAZY
    ))
    })
    List<User> findAllWithAccount();
    }
  • 编写账户的持久层接口并使用注解配置

    public interface AccountDAO {
    
        /**
    * 根据用户 id 查询用户下的所有账户
    * @param userId
    * @return
    */
    @Select("select * from account where uid = #{uid} ")
    List<Account> findByUid(Integer userId);
    }
  • 添加测试方法

    package cn.parzulpan;
    
    import cn.parzulpan.dao.UserDAO;
    import cn.parzulpan.domain.Account;
    import cn.parzulpan.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.List; /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc :
    */ public class MyBatisAccountManyTest {
    private InputStream is;
    private SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    private UserDAO userDAO; @Before
    public void init() throws Exception {
    System.out.println("Before...");
    is = Resources.getResourceAsStream("SqlMapConfig.xml");
    sqlSessionFactory = builder.build(is);
    sqlSession = sqlSessionFactory.openSession();
    userDAO = sqlSession.getMapper(UserDAO.class);
    } @After
    public void destroy() throws Exception {
    System.out.println("After...");
    sqlSession.commit();
    sqlSession.close();
    is.close();
    } @Test
    public void findAllWithAccountTest() {
    List<User> users = userDAO.findAllWithAccount();
    for (User user : users) {
    System.out.println();
    System.out.println(user);
    System.out.println(user.getAccounts());
    }
    }
    }

缓存配置

  • 在 SqlMapConfig 中开启二级缓存支持

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mabatis.org//DTD Congfig 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration>
    <!-- 配置二级缓存 -->
    <settings>
    <!-- 开启二级缓存的支持 -->
    <setting name="cacheEnabled" value="true"/>
    </settings>
    </configuration>
  • 在持久层接口中使用注解配置二级缓存

    @CacheNamespace(blocking = true)    // 基于注解方式实现配置二级缓存
    public interface UserDAO {
    }
  • 测试

    @Test
    public void findByIdHighCacheTest() {
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    UserDAO dao1 = sqlSession1.getMapper(UserDAO.class);
    User user1 = dao1.findById(41);
    System.out.println(user1.hashCode()); // 765284253
    sqlSession1.close(); // 一级缓存消失 SqlSession sqlSession2 = sqlSessionFactory.openSession();
    UserDAO dao2 = sqlSession2.getMapper(UserDAO.class);
    User user2 = dao2.findById(41);
    System.out.println(user2.hashCode()); // 1043351526
    sqlSession1.close(); // 一级缓存消失 System.out.println(user1 == user2); // false }

练习和总结

【MyBatis】MyBatis 注解开发的更多相关文章

  1. spring boot整合mybatis基于注解开发以及动态sql的使用

    让我们回忆一下上篇博客中mybatis是怎样发挥它的作用的,主要是三类文件,第一mapper接口,第二xml文件,第三全局配置文件(application.properties),而今天我们就是来简化 ...

  2. mybatis的注解开发之三种动态sql

    脚本sql XML配置方式的动态SQL我就不讲了,有兴趣可以自己了解,下面是用<script>的方式把它照搬过来,用注解来实现.适用于xml配置转换到注解配置 @Select(" ...

  3. mybatis学习:mybatis的注解开发和编写dao实现类的方式入门

    一.使用注解则不需要创建映射配置文件:即xxxDao.xml javaBean为什么要实现Serializable接口? Java的"对象序列化"能让你将一个实现了Serializ ...

  4. Mybatis使用注解开发(未完)

    使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心 注解在接口实现 @Select("SELECT * FROM user") Lis ...

  5. MyBatis使用注解开发

  6. mybatis学习:mybatis的注解开发CRUD操作

    Dao层: public interface IUserDao { /** * 查询所有结果 * @return */ @Select("select * from user") ...

  7. Mybatis注解开发模糊查询

    Mybatis注解开发模糊查询 一般在使用mybatis时都是采用xml文件保存sql语句 这篇文章讲一下在使用mybatis的注解开发时,如何进行模糊查询 模糊查询语句写法(在@Select注解中) ...

  8. 学习MyBatis必知必会(7)~注解开发、动态SQL

    一.MyBatis的注解开发 开发中推荐是使用xml文件配置 1.配置映射关系[使用注解的方式]: <!-- 全局的配置文件 --> <configuration> <! ...

  9. Spring+SpringMVC+MyBatis深入学习及搭建(十六)——SpringMVC注解开发(高级篇)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7085268.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十五)——S ...

  10. mybatis多参数传递,延迟加载,缓存,注解开发

    1.Mybatis的多参数传递方式 需求:更具id 和 名字查询用户: select * from user where id = ? and name = ?: 1):QueryVo 或者 User ...

随机推荐

  1. 最简 Spring AOP 源码分析!

    前言 最近在研究 Spring 源码,Spring 最核心的功能就是 IOC 容器和 AOP.本文定位是以最简的方式,分析 Spring AOP 源码. 基本概念 上面的思维导图能够概括了 Sprin ...

  2. 学习笔记:Link Cut Tree

    模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...

  3. 【题解】CIRU - The area of the union of circles [SP8073] \ 圆的面积并 [Bzoj2178]

    [题解]CIRU - The area of the union of circles [SP8073] \ 圆的面积并 [Bzoj2178] 传送门: \(\text{CIRU - The area ...

  4. AcWing 328. 芯片 (二进制写法)

    题目链接 我自闭了,调了一下午,我居然认为 \(2, 3\) 凑不出 \(7\),我怕是个孤儿. 这是一位非要用二进制写的勇士. 首先定义状态 \(S\),若 \(S\) 的二进制第 \(k\) 位为 ...

  5. 题解-CF677D Vanya and Treasure

    CF677D Vanya and Treasure 有一个 \(n\times m\) 的矩阵 \(a(1\le a_{i,j}\le p)\),求从起点 \((1,1)\) 出发依次遍历值为 \(1 ...

  6. Java中CAS原理分析(volatile和synchronized浅析)

    CAS是什么? CAS英文解释是比较和交换,是cpu底层的源语,是解决共享变量原子性实现方案,它定义了三个变量,内存地址值对应V,期待值E和要修改的值U,如下图所示,这些变量都是在高速缓存中的,如果两 ...

  7. WP | [MRCTF2020]Ezpop

    2020.10.14 最近开始努力提高代码能力 题目代码 Welcome to index.php <?php //flag is in flag.php //WTF IS THIS? //Le ...

  8. RabbitMq基本概念理解

    RabbitMQ的基本概念 RabbitMQ github项目地址 RabbitMQ 2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的 消息中间件 ...

  9. 测试提bug及出现漏测情况时的注意点

    提bug注意(此为公司开发提出的建议): 开发如果改bug影响导致另一个问题,原bug没有问题,尽量重新提bug,不要直接激活,因为可能不是同一个问题导致的:   不要一个bug里提多个问题,因为不同 ...

  10. 庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署

    庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署 一.简介      我们在上一篇文章<庐山真面目之八微服务架构 NetCore 基于 Dockerfile ...