在新建一个maven项目(不使用骨架),命名为mybatis_annotationTest,pom.xml文件配置如下:
<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.0modelVersion>
<groupId>com.stevensamgroupId>
<artifactId>mybatis_annotationTestartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>jarpackaging>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.6version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.5version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>utf-8encoding>
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 courseList;
//学生所选的课程分数类
private List 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 students;//班级的学生
@Override
public String toString() {
return "Classes{" +
"cid=" + cid +
", cname='" + cname + '\'' +
", cnum=" + cnum +
'}';
}
/***************get和set方法此处省略,请自行加载********************/
}
resources中复制之前项目的配置文件即可,如下图:
<configuration>
<properties resource="jdbcConfig.properties">properties>
<typeAliases>
<package name="com.stevensam.domain">package>
typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<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();
}
/**后续增加测试方法*/
}
查询所有学生
在IStudentDao接口中增加一个查询所有学生的方法
/**
* 查询所有操作
* 注解开发和xml文件开发最大的区别就是把查询语句用注解写在方法的上面
* @return
*/
@Select("select * from student")
List findAll();
在测试类AnnotationTest中增加测试查询所有学生的方法
/**
* 测试添加学生
*/
@Test
public void testFindAll(){
List 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 findByName(String name);
在测试类AnnotationTest中添加测试根据姓名模糊查询学生信息的方法
/**
* 测试根据姓名模糊查询学生
*/
@Test
public void testFindByName(){
List 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 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 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 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的入门知识点就先告一段落,当然有一些知识没有讲全,比如二级缓存,延迟加载是怎么样的机制,我希望读者可以自行了解,形成一个良好的学习习惯。在文章中间有一些问题或者是我说的不对的地方,可以发邮箱给我或者留言评论,我会一一回复,感谢。
邮箱地址[email protected]。