• 08 MyBatis 注解开发


    目录

    一、MyBatis注解开发介绍:

    二、MyBatis注解开发_增删改查

    1.在核心配置文件SqlMapConfig.xml中注册接口

    2.写一套增删改查

    (1)查询user表所有数据

    (2)向user表添加数据

    (3)根据id更新user表

    (4)根据id删除user表

    (5)模糊查询

    三、MyBatis注解开发_动态Sql

    1.使用脚本标签

    2.在方法中构建动态Sql

    四、MyBatis注解开发_自定义映射关系

    1.介绍

    2.用法如下:

    五、MyBatis注解开发_开启二级缓存

    1.pojo类实现Serializable接口

    2.在MyBatis配置文件中添加如下设置:

    3.在持久层接口上方加注解@CacheNamespace(blocking = true)为接口中所有方法开启二级缓存

    4.测试方法

    5.测试结果

    6.结论:

    六、MyBatis注解开发_关联查询

    1.一对一关联查询

    (1)创建实体类

    (2)在持久层接口中创建分解后的查询方法(包括主表的查询配置自定义映射关系)

    (3)测试方法

    2.一对多关联查询

    1.在持久层接口中创建分解后的查询方法(包括主表的查询配置自定义映射关系)

    2.测试方法

    七、注解和映射文件对比

    1.映射文件开发优点:

    2.注解开发优点:


    2.在方法中构建动态Sql

    四、MyBatis注解开发_自定义映射关系

    五、MyBatis注解开发_开启二级缓存

    六、MyBatis注解开发_关联查询

    七、注解和映射文件对比

    一、MyBatis注解开发介绍:

     MyBatis可以使用注解替代映射文件。映射文件的作用就是定义Sql 语句,可以在持久层接口上使用 @Select/@Delete/@Insert/@Update定义Sql语句,这样就不需要使用映射文件了,注解开发底层还是会转换为xml映射文件的方式

    二、MyBatis注解开发_增删改查

    1.在核心配置文件SqlMapConfig.xml中注册接口

    1. <mappers>
    2. <package name="com.itbaizhan.mapper"/>
    3. mappers>

    2.写一套增删改查

    (1)查询user表所有数据

    持久层接口方法

    1. // 查询user表所有数据
    2. @Select("select * from user")
    3. List findAll();

    测试方法

    1. public class TestUserMapper {
    2. InputStream is = null;
    3. SqlSession session = null;
    4. UserMapper userMapper = null;
    5. @Before
    6. public void testBefore() throws IOException {
    7. is = Resources.getResourceAsStream("SqlMapConfig.xml");
    8. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    9. SqlSessionFactory factory = builder.build(is);
    10. session = factory.openSession();
    11. userMapper = session.getMapper(UserMapper.class);
    12. }
    13. @After
    14. public void testAfter() throws IOException {
    15. session.close();
    16. is.close();
    17. }
    18. @Test
    19. public void testFindAll(){
    20. List all = userMapper.findAll();
    21. all.forEach(System.out::println);
    22. }
    23. }

    (2)向user表添加数据

    持久层接口方法

    1. // 主键回填
    2. @SelectKey(keyColumn = "id",keyProperty = "id", resultType = int.class,
    3. before = false, statement = "SELECT LAST_INSERT_ID()")
    4. // 向user表添加数据
    5. @Insert("insert into user(username,sex,address) values(#{username},#{sex},#{address})")
    6. void add(User user);

    测试方法

    1. @Test
    2. public void testAdd(){
    3. User user = new User("北京程序员","女","上海");
    4. System.out.println(user);
    5. userMapper.add(user);
    6. session.commit();
    7. System.out.println(user);
    8. }

    (3)根据id更新user表

    持久层接口方法

    1. // 根据id更新user表
    2. @Update("update user set username = #{username},sex = #{sex},address = #{address} where id = #{id}")
    3. void update(User user);

    测试方法

    1. @Test
    2. public void testUpdate(){
    3. User user = new User(4,"上海","男","北京");
    4. userMapper.update(user);
    5. session.commit();
    6. }

    (4)根据id删除user表

    持久层接口方法

    1. // 根据id删除user表
    2. @Delete("delete from user where id = #{id}")
    3. void delete(int userId);

    测试方法

    1. @Test
    2. public void testDelete(){
    3. userMapper.delete(21);
    4. session.commit();
    5. }

    (5)模糊查询

    持久层接口方法

    1. // 模糊查询
    2. @Select("select * from user where username like '%${value}%'")
    3. // @Select("select * from user where username like #{username}")
    4. List findByUsername(String username);

    测试方法

    1. @Test
    2. public void testFindByUsername(){
    3. List all = userMapper.findByUsername("上海");
    4. all.forEach(System.out::println);
    5. }

    三、MyBatis注解开发_动态Sql

     MyBatis注解开发中有两种方式构建动态Sql,1.使用脚本标签")

  • List findByCondition(User user);
  • 测试方法

    1. @Test
    2. public void testFindByCondition(){
    3. User user = new User();
    4. user.setUsername("%shanghai%");
    5. List all = userMapper.findByCondition(user);
    6. all.forEach(System.out::println);
    7. }

    2.在方法中构建动态Sql

    MyBatis 中有 @SelectProvider @UpdateProvider @DeleteProvider @InsertProvider 注 解。当使用这些注解时将不在注解中直接编写 SQL, 而是调用某个类的方法来生成SQL

    类方法

    1. public class UserProvider {
    2. public String findByConditionSql(User user){
    3. StringBuffer sb = new StringBuffer("select * from user where 1=1 ");
    4. if(user.getUsername() != null && user.getUsername().length() != 0){
    5. sb.append("and username like #{username}");
    6. }
    7. if(user.getSex() != null && user.getSex().length() != 0){
    8. sb.append("and sex = #{sex}");
    9. }
    10. if(user.getAddress() != null && user.getAddress().length() != 0){
    11. sb.append("and address = #{address}");
    12. }
    13. return sb.toString();
    14. }
    15. }

    持久层接口方法

    1. // 用动态SQL语句进行任意条件查询2
    2. @SelectProvider(type = UserProvider.class,method = "findByConditionSql")
    3. List findByCondition(User user);

    测试方法

    1. @Test
    2. public void testFindByCondition(){
    3. User user = new User();
    4. user.setUsername("%shanghai%");
    5. List all = userMapper.findByCondition(user);
    6. all.forEach(System.out::println);
    7. }

    四、MyBatis注解开发_自定义映射关系

    1. public class User implements Serializable {
    2. private int id;
    3. private String username;
    4. private String sex;
    5. private String address;
    6. //省略构造器、getter、setter、toString方法
    7. }

    1.介绍

     如上述代码图片所示,当POJO属性名与数据库列名不一致时,需要自定义实体类和结果集的映射关系,在MyBatis注解开发中,使用 @Results 定义并使用自定义映射,使用 @ResultMap 使用自定义映射。

    2.用法如下:

    持久层接口方法

    1. public interface UserMapper {
    2. //注解开发底层还是会转换为xml映射文件的方式
    3. // 自定义映射关系
    4. @Results(id = "userMapper", value = {
    5. @Result(id = true,property = "id", column = "id"),
    6. @Result(property = "username", column = "username1"),
    7. @Result(property = "sex", column = "sex1"),
    8. @Result(property = "address", column = "address1")
    9. })
    10. // 查询user表所有数据
    11. @Select("select * from user")
    12. List findAll();
    13. // 通过id查询user表中数据,使用resultMap注解来引用上述自定义的映射关系
    14. @ResultMap("userMapper")
    15. @Select("select * from user where id = #{id}")
    16. User findById(int userId);
    17. }

    测试方法

    1. @Test
    2. public void testFindAll(){
    3. List all = userMapper.findAll();
    4. all.forEach(System.out::println);
    5. }
    6. @Test
    7. public void testFindById(){
    8. User user = userMapper.findById(3);
    9. System.out.println(user);
    10. }

    五、MyBatis注解开发_开启二级缓存

    MyBatis 默认开启一级缓存,接下来我们来看在注解开发时如何使用二级缓存:

    1.pojo类实现Serializable接口

    1. public class User implements Serializable {
    2. private int id;
    3. private String username;
    4. private String sex;
    5. private String address;
    6. //省略构造器、getter、setter、toString方法
    7. }

    2.在MyBatis配置文件中添加如下设置:

    因为MyBatis是默认开启缓存的,所以这里可以不用配置

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

    3.在持久层接口上方加注解@CacheNamespace(blocking = true)为接口中所有方法开启二级缓存

    1. @CacheNamespace(blocking = true)
    2. public interface UserMapper {
    3. //省略接口方法
    4. }

    4.测试方法

    1. public class TestUserMapper2 {
    2. @Test
    3. public void testCache() throws IOException {
    4. InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
    5. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    6. SqlSessionFactory factory = builder.build(is);
    7. SqlSession session1 = factory.openSession();
    8. SqlSession session2 = factory.openSession();
    9. User user1 = session1.getMapper(UserMapper.class).findById(1);
    10. System.out.println(user1);
    11. System.out.println(user1.hashCode());
    12. session1.commit(); // 清空一次缓存,将数据存到二级缓存
    13. User user2 = session2.getMapper(UserMapper.class).findById(1);
    14. System.out.println(user2);
    15. System.out.println(user2.hashCode());
    16. }
    17. }

    5.测试结果

    6.结论:

    只执行了一次sql语句,第二次得到的数据是二级缓存中的,两个user对象的HashCode值不同是因为:一级缓存存的是对象,二级缓存存的是数据,从二级缓存中拿到数据后,会将数据再次封装为对象,所以两次HashCode值不同。

    六、MyBatis注解开发_关联查询

     在MyBatis的注解开发中对于多表查询只支持分解查询,不支持连接查询。

    1.一对一关联查询

    (1)创建实体类

    1. public class Student {
    2.    private int sid;
    3.    private String name;
    4.    private int age;
    5.    private String sex;
    6.    private Classes classes;
    7.    // 省略getter/setter/toString
    8. }
    9. public class Classes {
    10.    private int cid;
    11.    private String className;
    12.    private List students;
    13.    // 省略getter/setter/toString
    14. }

    (2)在持久层接口中创建分解后的查询方法(包括主表的查询配置自定义映射关系)

    1. public interface StudentMapper {
    2. // 一对一关联查询,查询学生并关联查询出班级(主表:Student)
    3. @Select("select * from student")
    4. // 自定义映射关系
    5. @Results(id = "studentMapper", value = {
    6. @Result(id = true,property = "sid", column = "sid"),
    7. @Result(property = "name", column = "name"),
    8. @Result(property = "age", column = "age"),
    9. @Result(property = "sex", column = "sex"),
    10. /**
    11. * property:属性名
    12. * column:关联列主键名
    13. * one:表示该属性是一个对象,即一对一关联查询
    14. * select:调用从表中的方法
    15. * fetchType:加载方式
    16. * eager:立即加载 lazy:懒加载(延迟加载)
    17. */
    18. @Result(property = "classes",column = "classId",
    19. one = @One(select = "com.itbaizhan.mapper.ClassesMapper.findByCid",
    20. fetchType = FetchType.EAGER))
    21. })
    22. List findAll();
    23. }
    1. public interface ClassesMapper {
    2. // 一对一关联查询,查询学生并关联查询出班级(从表:Classes)
    3. @Select("select * from classes where cid = #{cid}")
    4. Classes findByCid(int cid);
    5. }

    (3)测试方法

    1. @Test
    2. public void testFindAll(){
    3. StudentMapper studentMapper = session.getMapper(StudentMapper.class);
    4. List all = studentMapper.findAll();
    5. all.forEach(System.out::println);
    6. }

    2.一对多关联查询

    1.在持久层接口中创建分解后的查询方法(包括主表的查询配置自定义映射关系)

    1. public interface ClassesMapper {
    2. // 一对多关联查询,查询所有班级并关联查询出班级对应的学生(主表:Classes)
    3. @Select("select * from classes")
    4. @Results(id = "classesMapper", value = {
    5. @Result(id = true,property = "cid",column = "cid"),
    6. @Result(property = "className",column = "className"),
    7. //many:表示一对多查询,该属性是一个集合
    8. @Result(property = "studentList",column = "cid",
    9. many = @Many(select = "com.itbaizhan.mapper.StudentMapper.findByClassId",
    10. fetchType = FetchType.LAZY))
    11. })
    12. List findAllClasses();
    13. }
    1. public interface StudentMapper {
    2. // 一对多关联查询,查询所有班级并关联查询出班级对应的学生(从表:Student)
    3. @Select("select * from student where classId = #{classId}")
    4. List findByClassId(int classId);
    5. }

    2.测试方法

    1. // 一对多关联查询
    2. @Test
    3. public void testFindAllClasses(){
    4. ClassesMapper classesMapper = session.getMapper(ClassesMapper.class);
    5. List all = classesMapper.findAllClasses();
    6. all.forEach(System.out::println);
    7. }

    七、注解和映射文件对比

     MyBatis中更推荐使用映射文件开发,SpringSpringBoot更推荐注解方式。具体使用要视项目情况而定。它们的优点对比如下:

    1.映射文件开发优点:

    (1)代码与 Sql 语句是解耦的,修改时只需修改配置文件,无需修改源码。
    (2)Sql 语句集中,利于快速了解和维护项目。
    (3)级联查询支持连接查询和分解查询两种方式,注解开发只支持分解查询。

    2.注解开发优点:

    配置简单,开发效率高。
    类型安全,在编译期即可进行校验,不用等到运行时才发现错误。因为在编译期IDEA会发现编译错误并报错,xml文件不会报错。

  • 相关阅读:
    Webpack Sourcemap文件泄露漏洞
    用DIV+CSS技术设计的凤阳旅游网站(web前端网页制作课作业)HTML+CSS+JavaScript
    [C++数据结构](23)哈希:位图,布隆过滤器,哈希切割
    输出二叉树第K层结点
    【后端】HTTP 初识
    G:\r\tcga_example-master\scripts 生存分析 tcgaexample jimmy 存活分析 单条线生存分析
    Methoxy-PEG-PCL,Methoxy-PEG-Poly(ε-caprolactone)可以作为制备纳米颗粒的重要原料
    未来十年的Python前景会是什么样的?
    Redis-应用问题(缓存穿透/缓存击穿/缓存雪崩/分布式锁)
    使用流水线插件实现持续集成、持续部署
  • 原文地址:https://blog.csdn.net/m0_51697147/article/details/125991969