Mybatis入门(五)之注解开发

一、环境搭建
  1. 在新建一个maven项目(不使用骨架),命名为mybatis_annotationTest,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>com.stevensam</groupId>
       <artifactId>mybatis_annotationTest</artifactId>
       <version>1.0-SNAPSHOT</version>
       <packaging>jar</packaging>
       <dependencies>
           <dependency>
               <groupId>junit</groupId>
               <artifactId>junit</artifactId>
               <version>4.12</version>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>mysql</groupId>
               <artifactId>mysql-connector-java</artifactId>
               <version>5.1.6</version>
               <scope>runtime</scope>
           </dependency>
           <dependency>
               <groupId>log4j</groupId>
               <artifactId>log4j</artifactId>
               <version>1.2.17</version>
           </dependency>
           <dependency>
               <groupId>org.mybatis</groupId>
               <artifactId>mybatis</artifactId>
               <version>3.4.5</version>
           </dependency>
       </dependencies>
       <build>
           <plugins>
               <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <configuration>
                   <source>1.8</source>
                   <target>1.8</target>
                   <encoding>utf-8</encoding>
                 </configuration>
               </plugin>
           </plugins>
       </build>
    </project>
  2. 在main-java目录中建立com.stevensam.dao以及com.stevensam.domain两个包,在dao包中新建一个IStudentDao接口,可以先不写代码。

  3. domain包中建立实体类,可以将之前的项目的实体类复制粘贴过来,各个类的内容如下:

    package com.stevensam.domain;
    import java.io.Serializable;
    import java.util.Date;
    import java.util.List;
    /**
    * author:seven lin
    * date:2018/8/2411:11
    * description:学生类
    **/
    public class Student implements Serializable {
       private int sid;
       private String sname;
       private String sex;
       private Date birthday;
       private int cno;
       //学生所在班级
       private Classes cla;
       //学生所选课程
       private List<Course> courseList;
       //学生所选的课程分数类
       private List<StuCourse> stuCourseList;
       @Override
       public String toString() {
           return "Student{" +
                   "sid=" + sid +
                   ", sname='" + sname + '\'' +
                   ", sex='" + sex + '\'' +
                   ", birthday=" + birthday +
                   ", cno=" + cno +
                   '}';
       }
    /***************get和set方法此处省略,请自行加载*********************/
    }
    
    package com.stevensam.domain;
    import java.util.List;
    /**
    * author:seven lin
    * date:2018/8/2719:25
    * description:班级实体
    **/
    public class Classes {
       private int cid;
       private String cname;
       private int cnum;
       private List<Student> students;//班级的学生
       @Override
       public String toString() {
           return "Classes{" +
                   "cid=" + cid +
                   ", cname='" + cname + '\'' +
                   ", cnum=" + cnum +
                   '}';
       }
    /***************get和set方法此处省略,请自行加载********************/
    }
    
  4. resources中复制之前项目的配置文件即可,如下图:

    resources目录

    <?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>
       <!--如果用resource属性则可以直接写文件名jdbcConfig.properties-->
       <properties resource="jdbcConfig.properties"></properties>
       <!--只能给实体类区别名-->
       <typeAliases>
           <package name="com.stevensam.domain"></package>
       </typeAliases>
       <!--配置环境-->
       <environments default="mysql">
           <!--配置mysql的环境-->
           <environment id="mysql">
               <!--配置事务的类型-->
               <transactionManager type="JDBC"></transactionManager>
               <!--配置数据源(连接池)-->
               <dataSource type="POOLED">
                   <!--配置连接数据库的4个基本信息-->
                   <property name="driver" value="${jdbc.driver}"></property>
                   <property name="url" value="${jdbc.url}"></property>
                   <property name="username" value="${jdbc.username}"></property>
                   <property name="password" value="${jdbc.password}"></property>
               </dataSource>
           </environment>
       </environments>
       <mappers>
           <!--用别名更加简洁方便-->
           <package name="com.stevensam.dao"></package>
       </mappers>
    </configuration>
  5. test目录下,在java文件夹中添加com.stevensam.test文件夹,再建立AnnotationTest测试类进行测试,代码如下:

    package com.stevensam.test;
    
    import com.stevensam.dao.IStudentDao;
    import com.stevensam.domain.Student;
    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:seven lin
    * date:2018/8/2414:33
    * description:
    **/
    public class AnnotationTest {
    
       private InputStream in;
       private SqlSession session;
       private IStudentDao iStudentDao;
    
       @Before//在测试方法之前执行
       public void init() throws Exception {
           //1.读取配置文件
           in = Resources.getResourceAsStream("SqlMapConfig.xml");
           //2.创建SqlSessionFactory工厂
           SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
           SqlSessionFactory factory = builder.build(in);
           //3.工厂生产SqlSession对象
           session = factory.openSession();
           //4.使用SqlSession创建Dao接口的代理对象
           iStudentDao = session.getMapper(IStudentDao.class);
       }
       @After//在测试方法之后执行
       public void destroy() throws Exception {
           //6.释放资源
           in.close();
           session.close();
       }
       /**后续增加测试方法*/
    }
二、注解开发之CRUD操作
  1. 查询所有学生

    在IStudentDao接口中增加一个查询所有学生的方法

    /**
    * 查询所有操作
    * 注解开发和xml文件开发最大的区别就是把查询语句用注解写在方法的上面
    * @return
    */
    @Select("select * from student")
    List<Student> findAll();

    在测试类AnnotationTest中增加测试查询所有学生的方法

    /**
    * 测试添加学生
    */
    @Test
    public void testFindAll(){
       List<Student> studentList = iStudentDao.findAll();
       for(Student student:studentList){
           System.out.println(student);
       }
    }

    执行结果
    查询结果

  2. 增加一个学生

    在IStudentDao接口中增加一个增加学生的方法

    /**
    * 添加一个学生
    * @param student
    */
    @Insert("insert into student(sname,sex,birthday,cno) " +
           "values(#{sname},#{sex},#{birthday},#{cno})")
    void addStudent(Student student);

    在测试类AnnotationTest中增加测试查询所有学生的方法

    /**
    * 测试查询所有学生
    */
    @Test
    public void testAddStudent() throws Exception {
       Student student = new Student();
       student.setSname("徐盛");
       student.setSex("男");
       student.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("2000-02-03"));
       student.setCno(3);
       iStudentDao.addStudent(student);
    }

    执行结果
    插入结果

  3. 更改学生信息

    在IStudentDao中添加一个修改学生信息的方法

    /**
    * 修改学生信息
    * @param student
    */
    @Update("update student set sname=#{sname},sex=#{sex},birthday=#{birthday},cno=#{cno} " +
           "where sid=#{sid}")
    void updateStudent(Student student);

    在测试类AnnotationTest中添加测试修改学生信息的方法

    /**
    * 测试修改学生
    */
    @Test
    public void testUpdate() throws Exception {
       Student student = new Student();
       student.setSid(18);
       student.setSname("徐盛");
       student.setSex("女");
       student.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("2001-12-03"));
       student.setCno(1);
       iStudentDao.updateStudent(student);
       session.commit();
    }

    执行结果
    修改学生

  4. 删除学生信息

    在IStudentDao中添加一个删除学生信息的方法

    /**
        * 根据id删除学生
        * @param student
        */
    @Delete("delete from student where sid=#{sid}")
    void deleteStudent(Student student);

    在测试类AnnotationTest中添加测试删除学生的方法

    /**
        * 测试删除学生
        */
    @Test
    public void testDelete(){
       Student student = new Student();
       student.setSid(18);
       iStudentDao.deleteStudent(student);
       session.commit();
    }

    执行结果
    删除学生

  5. 模糊查询学生信息

    在IStudentDao中添加一个根据姓名模糊查询学生信息的方法

    /**
    * 根据姓名模糊查询学生
    * @param name
    * @return
    */
    @Select("select * from student where sname like #{sname}")
    List<Student> findByName(String name);

    在测试类AnnotationTest中添加测试根据姓名模糊查询学生信息的方法

    /**
    * 测试根据姓名模糊查询学生
    */
    @Test
    public void testFindByName(){
       List<Student> studentList = iStudentDao.findByName("%张%");
       for(Student student:studentList){
           System.out.println(student);
       }
    }

    执行结果
    模糊查询

  6. 统计学生人数

    在IStudentDao中添加一个统计学生人数的方法

    /**
        * 统计学生人数
        * @return
        */
    @Select("select count(*) from student")
    int countStundets();

    在测试类AnnotationTest中添加测试修改学生信息的方法

    /**
        * 测试统计人数
        */
    @Test
    public void testCountStudents(){
       System.out.println("学生总人数为:"+iStudentDao.countStundets());
    }

    执行结果
    统计人数

  7. 注意事项

    由于设置了事务管理,所以在操作的时候除了查询之外的语句,我们都需要添加提交的代码session.commit();

三、如何设置返回值

在实体类中的成员变量名和数据库中的列名不一致的时候,我们需要一一对应列名,在之前的文章中已经用了XML配置文件设置过,这次用注解开发又如何编写呢?请看下面的例子:

  1. 在查询所有学生的时候设置返回值对应列表

    假设学生类中的成员变量名不同,我这里将变量名改一下,并重新生成get和set方法,还有tostring方法,如下代码:

    private int id;//之前为sid
    private String name;//之前为sname
    /*******************省略其他成员变量********************/
    @Override
    public String toString() {
       return "Student{" +
           "id=" + id +
           ", name='" + name + '\'' +
           ", sex='" + sex + '\'' +
           ", birthday=" + birthday +
           ", cno=" + cno +
           '}';
    }

    接下来,在IStudentDao接口中修改findAll()方法,增加结果返回集注解,如下:

    /**
        * 查询所有操作.
        * Results可以用id命名,这里命名为studentMap,在其他方法中可以直接调用
        * @return
        */
       @Select("select * from student")
       @Results(id = "studentMap",value = {
               @Result(id=true,column = "sid",property = "sid"),
               @Result(column = "sname",property = "sname"),
               @Result(column = "sex",property = "sex"),
               @Result(column = "birthday",property = "birthday"),
               @Result(column = "cno",property = "cno")
       })
       List<Student> findAll();

    运行测试类中相应的测试方法,结果如下:
    结果集查询

  2. 第一例子中的结果集可以在其他方法使用,比如查询一个学生的方法

    在IStudentDao中添加方法

    /**
    * 根据id查询学生
    * @param integer
    * @return
    */
    @Select("select * from student where sid=#{id}")
    @ResultMap("studentMap")
    Student findById(Integer integer);

    AnnotationTest添加测试方法

    /**
    * 测试根据id查询学生
    */
    @Test
    public void testFindById(){
       System.out.println("学生:"+iStudentDao.findById(16));
    }

    执行结果
    id查询

  3. 在插入学生信息成功之后给返回该学生的id。

    这里的返回和上面的有点不同的是,方法是没有没有返回值的,依靠的是注解将值返回。而且有两种方式实现。

第一种:options,添加表的列名sid,指定成员变量的名id,关键的一步是设置useGeneratedKeys = true,直译过来就是要接代传递变量。

第二种:selectkey,基本的思路和xml配置一样,代码编写如下:

/**
     * 添加一个学生
     * @param student
     */
@Insert("insert into student(sname,sex,birthday,cno) " +
        "values(#{name},#{sex},#{birthday},#{cno})")
//@Options(useGeneratedKeys = true,keyColumn = "sid",keyProperty = "id")
@SelectKey(statement = "select last_insert_id()",keyProperty = "id",
           keyColumn = "sid",resultType = int.class,before = false)
void addStudent(Student student);

执行结果
插入结果1
4. 一对一关系映射one注解
在xml开发中,一对一关系映射查询,用的是association标签解决,而在注解开发用的是one注解。
以第一个例子来修改,在IStudentDao修改查询所有的操作:

/**
   * 查询所有操作
   * @return
   */
@Select("select * from student")
@Results(id = "studentMap",value = {
  @Result(id=true,column = "sid",property = "id"),
  @Result(column = "sname",property = "name"),
  @Result(column = "sex",property = "sex"),
  @Result(column = "birthday",property = "birthday"),
  @Result(column = "cno",property = "cno"),
  @Result(column = "cno",property = "cla",
/*select属性中填写执行方法的全限定类名加方法名,这里还开启了延迟加载(懒加载),在第四节会讲到
*/
one = @One(select = "com.stevensam.dao.IClasses.findByCId",
                     fetchType = FetchType.LAZY))
})
List<Student> findAll();

建立一个班级Dao接口

package com.stevensam.dao;
import com.stevensam.domain.Classes;
import org.apache.ibatis.annotations.Select;
/**
 * author:seven lin
 * date:2018/8/3010:59
 * description:班级实体类
 **/
public interface IClasses {

    /**
     * 根据id查询班级
     * @param i
     * @return
     */
    @Select("select * from classes where cid=#{cid}")
    Classes findByCId(int i);
}

在测试类中的测试方法添加打印该学生的班级信息

/**
 * 测试查询所有学生
 */
@Test
public void testFindAll(){
    List<Student> studentList = iStudentDao.findAll();
    for(Student student:studentList){
        System.out.println(student);
        System.out.println(student.getCla());//打印该学生对应的班级信息
    }
}

执行结果
这里写图片描述
结果可能大家会有点疑惑,为什么打印出来会不连续呢?而且查询班级的语句怎么只有三条,不应该是每次查询学生的时候就会触发查询班级的语句吗?
这里需要给大家讲的是缓存的知识,mybatis中默认开启一级缓存。一级缓存是存在于sqlsession中的,当同一个语句同一个条件要查询的时候,系统会缓存第一次查询执行对象,而第二次查询的时候就不需要再创建查询对象。比如,当执行select * from classes where cid=3时,那么第一次会执行,第二次不会再去创建对象执行,所以才会有以下的结果:
这里写图片描述
5. 一对多关系映射many注解
内容和one是差不多的,只是根据班级去查询学生,思路相反,没有很多不同。这里不演示了,留着给读者测试吧。

总结

mybatis的入门知识点就先告一段落,当然有一些知识没有讲全,比如二级缓存,延迟加载是怎么样的机制,我希望读者可以自行了解,形成一个良好的学习习惯。在文章中间有一些问题或者是我说的不对的地方,可以发邮箱给我或者留言评论,我会一一回复,感谢。
邮箱地址305105735@qq.com。

  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值