Mybatis入门(五)之注解开发
一、环境搭建
-
在新建一个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>
在main-java目录中建立com.stevensam.dao以及com.stevensam.domain两个包,在dao包中新建一个IStudentDao接口,可以先不写代码。
-
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方法此处省略,请自行加载********************/ }
-
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>
-
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操作
-
查询所有学生
在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); } }
执行结果
-
增加一个学生
在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); }
执行结果
-
更改学生信息
在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(); }
执行结果
-
删除学生信息
在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(); }
执行结果
-
模糊查询学生信息
在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); } }
执行结果
-
统计学生人数
在IStudentDao中添加一个统计学生人数的方法
/** * 统计学生人数 * @return */ @Select("select count(*) from student") int countStundets();
在测试类AnnotationTest中添加测试修改学生信息的方法
/** * 测试统计人数 */ @Test public void testCountStudents(){ System.out.println("学生总人数为:"+iStudentDao.countStundets()); }
执行结果
-
注意事项
由于设置了事务管理,所以在操作的时候除了查询之外的语句,我们都需要添加提交的代码session.commit();
三、如何设置返回值
在实体类中的成员变量名和数据库中的列名不一致的时候,我们需要一一对应列名,在之前的文章中已经用了XML配置文件设置过,这次用注解开发又如何编写呢?请看下面的例子:
-
在查询所有学生的时候设置返回值对应列表
假设学生类中的成员变量名不同,我这里将变量名改一下,并重新生成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();
运行测试类中相应的测试方法,结果如下:
-
第一例子中的结果集可以在其他方法使用,比如查询一个学生的方法
在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。
这里的返回和上面的有点不同的是,方法是没有没有返回值的,依靠的是注解将值返回。而且有两种方式实现。
第一种: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);
执行结果
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的入门知识点就先告一段落,当然有一些知识没有讲全,比如二级缓存,延迟加载是怎么样的机制,我希望读者可以自行了解,形成一个良好的学习习惯。在文章中间有一些问题或者是我说的不对的地方,可以发邮箱给我或者留言评论,我会一一回复,感谢。
邮箱地址aaa@qq.com。
上一篇: Mybatis入门
下一篇: MyBatis实现模糊查询的几种方式
推荐阅读
-
Java开发入门之第一阶段(五)
-
Spring+Spring MVC+Mybatis 框架整合开发(半注解半配置文件)
-
vue2.0开发实践总结之入门篇
-
MyBatis从入门到精通(八):MyBatis动态Sql之foreach标签的用法
-
Go语言开发之Windows 10中LiteIDE的入门教程
-
Spring的IOC注解开发入门1
-
JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识
-
IOS开发入门之storyboard的使用
-
Web前端开发入门技术之网页制作三要素
-
C语言编程入门之--第五章C语言基本运算和表达式-part1