zoukankan      html  css  js  c++  java
  • Mybatis注解开发

    一:引言

      通过前面的几篇文章的学习,到这里已经学习了差不多了,离成功也很快了,但还有Mybatis的注解开发要学习,因为学习注解开发,你就会发现原来Mybatis是这么牛逼呀,可以说使用注解开发会对你的开发起到了很大的时间缩减,接下来就由我给大家带来mybatis注解开发的一系列操作吧!

    准备工作【搭建简单注解框架

    二:Mybatis注解开发之单表CRUD操作

    因为单表的CRUD操作比较简单,我就直接上代码了,再加上一点注释

    1:查询一系列操作

    ①:查询全部

    ######StudentDao代码
    
    //查询全部学生数据
        @Select("select sid id,sname name,ssex sex,scredit credit,smoney " +
                "money,saddress address,senrol enrol, fid,tid from student")
        List<Student> findAll();
    
    ######测试类
        //查询全部学生
        @Test
        public void findAllStudent() {
            StudentDao mapper = sqlSession.getMapper(StudentDao.class);
            List<Student> students = mapper.findAll();
            for (Student student : students) {
                System.out.println(student);
            }
        }
    
    
    //可以看出这种使用别名的效果极差,如果字段多的话就会崩溃
    
    //在这个例子中展现出我的sql语句都是使用别名,要不然和类属性名和数据库字段名对不上,
    //所以我先用别名来解决这个问题,但是它肯定有简单的解决方法,再第三节我将为大家介绍注解映射关系
    查询全部

    ②:根据主键查询单个学生

    #####StudentDao接口代码  后面会介绍映射
    
    //查询单个 根据主键id
        @Select("select * from student where sid=#{id}")
        @Results(value={
                @Result(id=true,column = "sid",property = "id"),
                @Result(column = "sname",property = "name"),
                @Result(column = "ssex",property = "sex"),
                @Result(column = "sage",property = "age"),
                @Result(column = "scredit",property = "credit"),
                @Result(column = "smoney",property = "money"),
                @Result(column = "saddress",property = "address"),
                @Result(column = "senrol",property = "enrol"),
                @Result(column = "tid",property = "tid"),
                @Result(column = "fid",property = "fid")
        })
        Student findById(Integer id);
    
    
    #####测试类
    
        //查询单个学生
        @Test
        public void findById(){
            StudentDao mapper = sqlSession.getMapper(StudentDao.class);
            Student student = mapper.findById(5);
            System.out.println(student);
        }
    根据主键查询

    ③:模糊查询

    #####StudentDao接口代码
    
    //模糊查询 按照姓名   ResultMap是引用之前的映射
        @Select("select * from student where sname like #{name}")
        @ResultMap(value="studentMapper")
        List<Student> findLikeName(String name);
    
    #####测试类
        //模糊查询 按照学生姓名
        @Test
        public  void findLikeNameStudent(){
            StudentDao mapper = sqlSession.getMapper(StudentDao.class);
            List<Student> students = mapper.findLikeName("%张%");
            for (Student student : students) {
                System.out.println(student);
            }
        }
    模糊查询学生根据姓名

     注:模糊查询和之前配置文件的写法一样,也是有3种不同的写法,而我在这使用了占位符的方式

    ④:查询总记录数

    #####StudentDao接口代码
    
     //查询total总数
        @Select("select count(sid) from student")
        Integer total();
    
    
    #####测试
        //查询学生总数
        @Test
        public void  totalStudent(){
            StudentDao mapper = sqlSession.getMapper(StudentDao.class);
            Integer total = mapper.total();
            System.out.println("总共学生:"+total);
        }
    查询学生总记录数

    2:添加操作

    #####dao代码
    
    //添加学生
        @Insert("insert into student(sname,ssex,sage,scredit,smoney,saddress,senrol,fid,tid)" +
                " values (#{name},#{sex},#{age},#{credit},#{money},#{address},#{enrol},null,#{tid})")
        void add(Student student);
    
    
    //注:因为学生表中有一个一对一的字段外键fid指向家庭信息表,所以我之
    //前在设计表的时候对学生表和家庭信息表的外键做了约束,删除制空,更改级联,所以我给家庭信息表设置了null
    
    ######测试
    //添加学生
        @Test
        public void insertStudent(){
            Student student=new Student(0,"蚂蚁小哥","男",16,55,688.5,"安徽六安","2018-9-9",0,2);
            StudentDao mapper = sqlSession.getMapper(StudentDao.class);
            mapper.add(student);
            sqlSession.commit();
        }
    添加数据

    3:更改操作

    #########dao接口
    
    //更新学生姓名  地址
        @Update("update student set sname=#{name},saddress=#{address} where sid=#{id}")
        void update(Student student);
    
    
    ######测试类
    //更新学生
        @Test
        public void updateStudent(){
            Student student=new Student();
            student.setName("小老虎");
            student.setId(2);
            student.setAddress("北京顺义");
            StudentDao mapper = sqlSession.getMapper(StudentDao.class);
            mapper.update(student);
            sqlSession.commit();
        }
    更新数据

    4:删除操作

    #####dao方法
    
    //删除学生
        @Delete("delete from student where sid=#{id}")
        void delete(Integer id);
    
    ########测试类
    //注:这里说明一下,删除的时候,因为我表设置一对一关系,所以删除的时候,
    //必须删除fid字段(连接家庭信息表)为空值的,就是后来添加的没用值
    
     //删除学生
        @Test
        public void deleteStudent(){
            StudentDao mapper = sqlSession.getMapper(StudentDao.class);
            mapper.delete(66);
            sqlSession.commit();
        }
    删除操作

    三:Mybatis注解配置映射关系

      众所周知,在Mybatis的xml编写中遇到数据库字段名和实体类属性名不一样怎么解决呢?最简单的方法就是写sql里面别名咯,这是最简单的,但是还有一种就是配置映射关系,使用resultMap标签来配置映射关系,好了,那注解开发怎么来配置呢?很简单,接下来就和我一起来看看吧!

    #首先呢在xml里面是标签,而在注解里面是@xxx什么的,所以@Results注解诞生了
    @Select("select * from student where sid=#{id}")
        @Results()
        Student findById(Integer id);
    
    #那里面可以放什么呢?怎么设置配置注解呢?
    点进去@Results注解可以看到当前注解是接口里面有2个方法
    //存放id的,用来标识唯一的配置信息,供其它的方法使用,不用来回配置了
    String id() default "";
    //存放映射关系的数组
    Result[] value() default {};
    
    
    #所以就改造成了这样,但是value里面怎么放呢?
    @Results(id="studentMapper",value={})
    
    
    #继续改造
    #Result就是配置每个关系的映射情况 点进去Result会发现好多接口方法
    //  用来配置当前字段是不是表的主键
    // boolean id() default false;
    //  配置数据库字段名称
    // String column() default "";
    //  配置实体类属性
    // String property() default "";
    //  java类型 说明当前实体类的属性类型
    // Class<?> javaType() default void.class;
    //  jdbc类型就是,当前的数据库字段类型
    // JdbcType jdbcType() default JdbcType.UNDEFINED;
    //  我们在前面讨论过默认的类型处理器。使用这个属性,
    //  你可以覆盖默认的类型处理器。这个属性值是类的完全
    //  限定名或者是一个类型处理器的实现,或者是类型别名
    // Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
    //  配置一对一关系
    // One one() default @One;
    //  配置一对多关系
    // Many many() default @Many;
    @Results(id="studentMapper",value={
                @Result(id=true,column = "sid",property = "id"),
                @Result(column = "sname",property = "name")
        })
    
    # 最终改造
    @Select("select * from student where sid=#{id}")
        @Results(id="studentMapper",value={
                @Result(id=true,column = "sid",property = "id"),
                @Result(column = "sname",property = "name"),
                @Result(column = "ssex",property = "sex"),
                @Result(column = "sage",property = "age"),
                @Result(column = "scredit",property = "credit"),
                @Result(column = "smoney",property = "money"),
                @Result(column = "saddress",property = "address"),
                @Result(column = "senrol",property = "enrol"),
                @Result(column = "tid",property = "tid"),
                @Result(column = "fid",property = "fid")
        })
        Student findById(Integer id);
    
    
    # 后期有要用这个注解的怎么办呢?
    # 因为ResultMap注解里面就一个属性方法可以不写value
    # @ResultMap{{"studentMapper"}}
    # 因为就一个值 所以花括号也可以省
    # @ResultMap{"studentMapper"}
    //模糊查询 按照姓名 @Select("select * from student where sname like #{name}") @ResultMap(value={"studentMapper"}) List<Student> findLikeName(String name);

    四:Mybatis注解之一对一查询

    Mybatis注解一对一查询就好像和使用xml的关联嵌套查询一样,都是调用别的方法直接查询,下面就带大家改造一下代码吧!

    ##### StudentDao接口
    //因为Student里面不包含family对象,所以定义了POJO对象
    //定义一个查询全部的方法,把数据封装到POJO对象里面
    //这里进行一个学生对应一个家庭信息数据的一对一操作
    //one代表一对一或者多对一操作使用的关联关系
    //one里面的select代表引用别处的查询家庭信息根据id
    //one里面的fetchType代表加载时机 因为是一对一我就使用了立即加载
    @Select("select * from student")
    @Results(id="studentMapper2",value={
            @Result(id=true,column = "sid",property = "id"),
            @Result(column = "sname",property = "name"),
            @Result(column = "ssex",property = "sex"),
            @Result(column = "sage",property = "age"),
            @Result(column = "scredit",property = "credit"),
            @Result(column = "smoney",property = "money"),
            @Result(column = "saddress",property = "address"),
            @Result(column = "senrol",property = "enrol"),
            @Result(column = "fid" ,property = "family",one=@One(select = "cn.xw.dao.FamilyDao.findById",fetchType = FetchType.EAGER))
    })
    List<Stu_Tea_Fam> findAllToStu_Tea_Fam();
    
    
    ##### FamilyDao接口  可以让上面的方法关联下面的查询方法
    //查询单个家庭信息
    @Select("select * from family where fid=#{id}")
    @Results(id = "familyMapper", value = {
            @Result(id = true, column = "fid", property = "id"),
            @Result(column = "fmember", property = "member"),
            @Result(column = "fguardian", property = "guardian"),
            @Result(column = "ftel", property = "tel"),
            @Result(column = "fdad", property = "dad"),
            @Result(column = "fmom", property = "mom"),
            @Result(column = "faddress", property = "address")
    })
    Family findById(Integer id);
    
    
    #####测试类
    //查询单个家庭信息
    @Test
    public void findByIdFamily() {
        FamilyDao mapper = sqlSession.getMapper(FamilyDao.class);
        Family family = mapper.findById(5);
        System.out.println(family);
    }
    
    //查询全部学生封装到POJO对象   主要是这个方法测试一对一的存在
    @Test
    public void findAllToStu_Tea_Fam() {
        StudentDao mapper = sqlSession.getMapper(StudentDao.class);
        List<Stu_Tea_Fam> students = mapper.findAllToStu_Tea_Fam();
        for (Stu_Tea_Fam student : students) {
            System.out.println(student);
        }
    }

    五:Mybatis注解之一对多查询

    注解一对多查询和xml的的集合关联查询差不多,都是在主表中调用查询副表的查询单个方法来封装到POJO对象

    ##### TeacherDao接口
    //查询全部辅导员,一对多  一个辅导员有多个学生
    //所以在主表中直接查询辅导员全部信息,
    //然后去调用副表的查询,把数据查询后封装
    //many是一对多 或者 多对多的查询
    //select是调用student
    //Dao里面的根据tid外键查询多个
    //fetchType 因为是一对多 推荐使用延迟加载 LAZY
        @Select("select * from teacher")
        @Results(id="studentMapper" , value={
                @Result(id=true,column = "tid",property = "id"),
                @Result(column = "tname",property = "name"),
                @Result(column = "tsex",property = "sex"),
                @Result(column = "tage",property = "age"),
                @Result(column = "tsalary",property = "salary"),
                @Result(column = "taddress",property = "address"),
                @Result(column = "tid",property = "students",many = @Many(select = "cn.xw.dao.StudentDao.findByTid",fetchType = FetchType.LAZY))
        })
        List<Tea_Stu> findAllToTea_Stu();
    
    
    ##### StudentDao接口
    //查询单个 根据外键id ,这里使用了ResultMap 代表它引用别的映射关系 
        @Select("select * from student where tid=#{id}")
        @Results(id="studentMapper3",value={
                @Result(id=true,column = "sid",property = "id"),
                @Result(column = "sname",property = "name"),
                @Result(column = "ssex",property = "sex"),
                @Result(column = "sage",property = "age"),
                @Result(column = "scredit",property = "credit"),
                @Result(column = "smoney",property = "money"),
                @Result(column = "saddress",property = "address"),
                @Result(column = "senrol",property = "enrol"),
                @Result(column = "tid",property = "tid"),
                @Result(column = "fid",property = "fid")
        })
        List<Student> findByTid(Integer id);
    
    
    ##### 测试方法
    //查询全部辅导员及学生
        @Test
        public void findAllToTea_Stu(){
            TeacherDao mapper = sqlSession.getMapper(TeacherDao.class);
            List<Tea_Stu> teachers = mapper.findAllToTea_Stu();
            for(Tea_Stu teacher:teachers){
                System.out.println(teacher);
            }
        }

     六:Mybatis之缓存机制

    1:一级缓存

    在上一篇文章也说过,Mybatis的一级缓存存在于SqlSession域的,它模式是开启状态,争夺以上我来演示一下

    ######更改一下StudentDao接口的方法 设置映射关系
    
    //查询单个 根据主键id 对映射关系我引用其它已经配置好的
        @Select("select * from student where sid=#{id}")
        @ResultMap("studentMapper")
        Student findById(Integer id);
    #####编写测试类
       
     //查询单个学生
        @Test
        public void findById() {
            //创建第一个SqlSession下的代理对象
            StudentDao mapper1 = sqlSession.getMapper(StudentDao.class);
            Student student1 = mapper1.findById(5);
            System.out.println("打印Student1的hashCode:"+student1.hashCode());
    
            //创建第二个SqlSession下的代理对象
            StudentDao mapper2 = sqlSession.getMapper(StudentDao.class);
            Student student2 = mapper2.findById(5);
            System.out.println("打印Student2的hashCode:"+student2.hashCode());
    
            System.out.println("看看2个对象是否一样");
            System.out.println(student1==student2);
        }

     但是要怎么要清除缓存呢?其实和之前的一篇文章一样,遇到增删改、commit、clearCache、close等都会使缓存消失

        //查询单个学生
        @Test
        public void findById() {
            //创建第一个SqlSession下的代理对象
            StudentDao mapper1 = sqlSession.getMapper(StudentDao.class);
            Student student1 = mapper1.findById(5);
            System.out.println("打印Student1的hashCode:"+student1.hashCode());
            
            //加上清除缓存方法
            sqlSession.clearCache();
    
            //创建第二个SqlSession下的代理对象
            StudentDao mapper2 = sqlSession.getMapper(StudentDao.class);
            Student student2 = mapper2.findById(5);
            System.out.println("打印Student2的hashCode:"+student2.hashCode());
    
            System.out.println("看看2个对象是否一样");
            System.out.println(student1==student2);
        }
    清除缓存方法代码

    2:二级缓存

    二级缓存其实默认为关闭的,要我们手动开启,这一点和xml配置做法一样,都要去SqlMapConfig.xml里面设置settings标签,唯一区别就是xml文件里配置cache标签,而注解要配置@CacheNamespace(blockint=true),接下来我就和大家来解释一下吧!

    #####第一步大家先配置一下SqlMapConfig.xml里面的settings标签
    
    <!--配置settings  记住一定要在Properties标签下面-->
        <settings>
            <setting name="cacheEnabled" value="true"/>
        </settings>
    
    
    #####第二步在实体类要实现序列化
    public class Student implements Serializable {
         ..........  
    }
    
    #####第三步在要实现二级缓存的接口上开启二级缓存的注解
    @CacheNamespace(blocking = true)
    public interface StudentDao {
          ..........  
    }    
    ###StudentDao接口方法   
    
     //查询单个 根据主键id
        @Select("select * from student where sid=#{id}")
        @ResultMap("studentMapper")
        Student findById(Integer id);
    
    
    
    #####测试类
    
     //查询单个学生
        @Test
        public void findById() {
            //因为测试方法结束后要关闭sqlSession对象,因为没有我创建一个
            sqlSession=factory.openSession();
    
            //创建第一个SqlSession对象
            SqlSession sqlSessionA = factory.openSession();
            StudentDao mapperA = sqlSessionA.getMapper(StudentDao.class);
            Student studentA = mapperA.findById(5);
            System.out.println("打印studentA的hashCode:"+studentA.hashCode());
            sqlSessionA.close();
    
            //创建第二个SqlSession对象
            SqlSession sqlSessionB = factory.openSession();
            StudentDao mapperB = sqlSessionB.getMapper(StudentDao.class);
            Student studentB = mapperB.findById(5);
            System.out.println("打印studentB的hashCode:"+studentB.hashCode());
            sqlSessionA.close();
    
            System.out.println("打印2者是否一样");
            System.out.println(studentA==studentB);
         //false是因为SqlSessionFactory域对象存储的是散装数据,具体前面一篇文章有详细介绍 }

     七:总结

      我在这几天中对Mybatis进行了一番讲解,从简单的入门到配置文件xml开发的CRUD操作以及单表多表的操作,但是这只是对Mybatis的基本操作;后面我又介绍了关于Mybatis的连接池技术以及源码的分析、加载机制和缓存机制,这才算的上对mybatis的一点点认识,但是今天我讲到了Mybatis的注解开发,其实呢注解开发固然好用,但是发现了吗?如果CRUD的方法特别多,都写注解sql,会发现它们的耦合关系太大,也难以看懂,所以具体看项目要求,我一般是单表操作的话注解开发可以推荐,但是呢,如果方法多,逻辑特别多,而且涉及到3表操作4表操作....我还是建议用xml开发

      说到这也结束了,后期我会慢慢的给大家带来mybatis的源码分析文章,谢谢大家,而且我能力有限,也是个小白,所以就没有讲的太深入,请大家理解

  • 相关阅读:
    bfs两种记录路径方法
    次小生成树
    2018 ICPC 区域赛 焦作场 D. Keiichi Tsuchiya the Drift King(计算几何)
    数组分组
    POJ
    数位DP详解
    2018ICPC青岛 E
    HDU
    Google工程师打造Remix OS系统 桌面版安卓下载
    使用angular封装echarts
  • 原文地址:https://www.cnblogs.com/antLaddie/p/12801945.html
Copyright © 2011-2022 走看看