[关闭]
@qdlxsxj 2016-05-29T14:19:50.000000Z 字数 38020 阅读 1004

MyBaits3基础培训


MyBatis

  • MyBaits简介
  • HelloWorld实现
  • 配置文件讲解
    • enviromenets
    • transactionManager
    • dataSource
    • properties
    • typeAliases
    • mappers
  • XML配置SQL映射器
    • INSERT映射语句
    • UPDATE映射语句
    • DELETE映射语句
    • SELECT映射语句
  • MyBatis关系映射
    • 一对一关系
    • 一对多关系
  • Mybatis动态SQL
    • if条件
    • choose,when,otherwrise
    • where
    • trim
    • foreach
    • set
  • MyBatis其他
    • CLOB类型处理
    • BLOB类型处理
    • MyBatis分页
    • MyBatis缓存
  • 注解配置SQL映射器
    • 基本映射语句
      • @INSERT
      • @UPDATE
      • @DELETE
      • @SELECT
    • 结果集映射
    • 关系映射
      • 一对一关系
      • 一对多关系
    • 动态SQL
      • @InsertProvider
      • @UpdateProvider
      • @DeleteProvider
      • @SelectProvider
  • MyBatis与Spring,Struts2整合
    • Spring与Struts整合
    • Spring与MyBatis整合

MyBaits简介

具体介绍查看百度百科,或者直接查看官网介绍。

HelloWorld实现

我们将采用最原始的JavaProject来构建项目,已达到最原始的使用体验,具体的构建过程不再赘述,所有内容将围绕MyBatis展开,一下所有方式均采用最佳实践,不常用的方法将不再赘述

开始之前,我们需要准备一个MySql数据库,并新建一张 t_student 表供测试用,后续我们的表结构会慢慢发生变化,并且表的数量也会增加

  1. CREATE DATABASE DEFAULT CHARACTER SET utf8 ;
  2. USE `db_mybatis`;
  3. DROP TABLE IF EXISTS `t_student`;
  4. CREATE TABLE `t_student` (
  5. `id` int(11) NOT NULL AUTO_INCREMENT,
  6. `name` varchar(20) DEFAULT NULL,
  7. `age` int(11) DEFAULT NULL,
  8. PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
  10. insert into `t_student`(`id`,`name`,`age`) values
  11. (1,'张三',10),(2,'李四',11),(3,'李四',11),(4,'李四',11),
  12. (5,'李四',11),(6,'李四',11),(7,'李四',11);

然后新建一个JavaProject MB_01,项目结构如下:

  1. MB_01
  2. --src
  3. --com.sue.demo
  4. --mappers
  5. --StudentMapper.java
  6. --StudentMapper.xml
  7. --model
  8. --Studnet.java
  9. --service
  10. --Test.java
  11. --util
  12. --SqlSessionFactoryUtil.java
  13. --lib
  14. --mysql-connector-java-3.1.12-bin.jar
  15. --mybatis-3.2.8.jar
  16. --jdbc.properties
  17. --mybatis-config.xml

配置 jdbc.properties

  1. jdbc.driverClassName=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/db_mybatis
  3. jdbc.username=root
  4. jdbc.password=

配置 mybaties-config.xml ,该配置文件中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务范围和控制方式的事务管理器(TransactionManager)。XML 配置文件的详细内容后面再探讨,这里先给出一个简单的示例:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <properties resource="jdbc.properties"></properties>
  7. <typeAliases>
  8. <package name="com.sue.mybatis.demo.model"/>
  9. </typeAliases>
  10. <environments default="developer">
  11. <environment id="developer">
  12. <transactionManager type="JDBC"></transactionManager>
  13. <dataSource type="POOLED">
  14. <property name="driver" value="${jdbc.driverClassName}"/>
  15. <property name="url" value="${jdbc.url}"/>
  16. <property name="username" value="${jdbc.username}"/>
  17. <property name="password" value="${jdbc.password}"/>
  18. </dataSource>
  19. </environment>
  20. </environments>
  21. <mappers>
  22. <package name="com.sue.mybatis.demo.mapper"/>
  23. </mappers>
  24. </configuration>

当然,还有很多可以在XML 文件中进行配置,上面的示例指出的则是最关键的部分。要注意 XML 头部的声明,用来验证 XML 文档正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则是包含一组 mapper 映射器(这些 mapper 的 XML 文件包含了 SQL 代码和映射定义信息)。

创建 Student.java

  1. public class Student {
  2. private Integer id;
  3. private String name;
  4. private Integer age;
  5. public Student() {
  6. super();
  7. }
  8. public Student(String name, Integer age) {
  9. super();
  10. this.name = name;
  11. this.age = age;
  12. }
  13. public Integer getId() {
  14. return id;
  15. }
  16. public void setId(Integer id) {
  17. this.id = id;
  18. }
  19. public String getName() {
  20. return name;
  21. }
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. public Integer getAge() {
  26. return age;
  27. }
  28. public void setAge(Integer age) {
  29. this.age = age;
  30. }
  31. }

为了方便测试,不用每次都书写重复获取 SqlSession 的代码,我们创建 SqlSessionFactoryUtils.java 用于获取SqlSession

  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import org.apache.ibatis.io.Resources;
  4. import org.apache.ibatis.session.SqlSession;
  5. import org.apache.ibatis.session.SqlSessionFactory;
  6. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  7. public class SqlSessionFactoryUtils {
  8. public static SqlSessionFactory sqlSessionFactory;
  9. public static SqlSessionFactory getSqlSessionFactory(){
  10. if(sqlSessionFactory == null){
  11. InputStream is = null;
  12. try {
  13. is = Resources.getResourceAsStream("mybatis-config.xml");
  14. sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. return sqlSessionFactory;
  20. }
  21. public static SqlSession opSession(){
  22. return getSqlSessionFactory().openSession();
  23. }
  24. }

创建 StudentMapper.java (后面基本每建一张表,我们就会新增一个对应的POJO类)

  1. import com.sue.mybatis.demo.model.Student;
  2. public interface StudentMapper {
  3. public int add(Student student);
  4. }

创建 StudentMapper.xml
<mapper namespace="com.sue.mybatis.demo.mapper.StudentMapper"> namespace 对应唯一的Interface接口
<insert id="add"> id 对应上述接口中的唯一方法

  1. <!DOCTYPE mapper
  2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.sue.mybatis.demo.mapper.StudentMapper">
  5. <insert id="add" parameterType="Student" useGeneratedKeys="true" keyProperty="id">
  6. insert into t_student(name, age) values(#{name}, #{age})
  7. </insert>
  8. </mapper>

创建测试类Test.java,并运行

  1. import org.apache.ibatis.session.SqlSession;
  2. import com.sue.mybatis.demo.mapper.StudentMapper;
  3. import com.sue.mybatis.demo.model.Student;
  4. import com.sue.mybatis.demo.util.SqlSessionFactoryUtils;
  5. public class Test {
  6. public static void main(String[] args) {
  7. SqlSession sqlSession = SqlSessionFactoryUtils.opSession();
  8. StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
  9. Student s = new Student("wangwu---", 11);
  10. studentMapper.add(s);
  11. sqlSession.commit();
  12. System.out.println(s.getId());
  13. }
  14. }

配置文件讲解

以下讲解均是相对于mybatis-config.xml中的标签

enviromenets

该标签下可以存在多个 environment ,实际开发一般都存在3个环境:开发环境(dev),生产环境(pro),测试环境(test),这时可以在 environments 中配置3个 environment,通过 environmentsdefault 属性指定所用环境

  1. <environments default="developer">
  2. <environment id="developer">
  3. <transactionManager type="JDBC"></transactionManager>
  4. <dataSource type="POOLED">
  5. <property name="driver" value="${jdbc.driverClassName}"/>
  6. <property name="url" value="${jdbc.url}"/>
  7. <property name="username" value="${jdbc.username}"/>
  8. <property name="password" value="${jdbc.password}"/>
  9. </dataSource>
  10. </environment>
  11. <environment id="production">
  12. <transactionManager type="JDBC"></transactionManager>
  13. <dataSource type="POOLED">
  14. <property name="driver" value="${jdbc.driverClassName}"/>
  15. <property name="url" value="${jdbc.url}"/>
  16. <property name="username" value="${jdbc.username}"/>
  17. <property name="password" value="${jdbc.password}"/>
  18. </dataSource>
  19. </environment>
  20. <environment id="test">
  21. <transactionManager type="JDBC"></transactionManager>
  22. <dataSource type="POOLED">
  23. <property name="driver" value="${jdbc.driverClassName}"/>
  24. <property name="url" value="${jdbc.url}"/>
  25. <property name="username" value="${jdbc.username}"/>
  26. <property name="password" value="${jdbc.password}"/>
  27. </dataSource>
  28. </environment>
  29. </environments>

transactionManager

MyBatis支持2种类型是事物管理器:JDBCMANAGED(托管)

  1. <transactionManager type="JDBC" />

dataSource

数据源配置,类型有:UNPOOLEDPOOLEDJNDI

  1. <dataSource type="POOLED">
  2. <property name="driver" value="${jdbc.driverClassName}"/>
  3. <property name="url" value="${jdbc.url}"/>
  4. <property name="username" value="${jdbc.username}"/>
  5. <property name="password" value="${jdbc.password}"/>
  6. </dataSource>

properties

属性配置,建议采用下面写法

  1. <properties resource="jdbc.properties"></properties>

typeAliases

给类的完全限定名取别名,建议采用下面写法

  1. <typeAliases>
  2. <package name="com.sue.mybatis.demo.model"/>
  3. </typeAliases>

mappers

引入映射文件,建议采用下面写法

  1. <mappers>
  2. <package name="com.sue.mybatis.demo.mapper"/>
  3. </mappers>

XML配置SQL映射器

这是我喜欢MyBatis的地方之一,结合动态SQL我可以完全管理自己的SQL语句,再也不同担心Hibernate复杂的关系了,语句调优难问题了

开始之前,我们先在 StudentMapper.java 中新增几个常用方法,后面每一小节只需着重针 StudentMapper.xml 的配置和测试用例即可

  1. public interface StudentMapper {
  2. public int add(Student student);
  3. public int update(Student student);
  4. public int delete(Integer id);
  5. public Student findById(Integer id);
  6. public List<Student> findAll();
  7. }

INSERT映射语句

  1. <insert id="add" parameterType="Student" useGeneratedKeys="true" keyProperty="id">
  2. insert into t_student(name ,age) values (#{name} ,#{age})
  3. </insert>

UPDATE映射语句

  1. <update id="update" parameterType="Student">
  2. update t_student set name=#{name},age=#{age}
  3. where id=#{id}
  4. </update>

DELETE映射语句

  1. <delete id="delete" parameterType="Integer">
  2. delete from t_student where id=#{id}
  3. </delete>

SELECT映射语句

findAll 中返回的集合可以用到 resultMap,此处先熟悉,后续复杂返回需要频繁使用,这个标签将伴随着你的开发生涯

  1. <resultMap type="Student" id="StudentResult">
  2. <id property="id" column="id"/>
  3. <result property="name" column="name"/>
  4. <result property="age" column="age"/>
  5. </resultMap>
  1. <select id="findById" parameterType="Integer" resultType="Student">
  2. select * from t_student where id=#{id}
  3. </select>
  4. <select id="findAll" resultMap="StudentResult">
  5. select * from t_student
  6. </select>

测试案例

  1. public class StudentTest2 {
  2. private SqlSession sqlSession = null;
  3. private StudentMapper sm = null;
  4. @Before
  5. public void setUp() throws Exception {
  6. sqlSession = SqlSessionFactoryUtil.openSession();
  7. sm = sqlSession.getMapper(StudentMapper.class);
  8. }
  9. @Test
  10. public void testAdd() {
  11. Student s = new Student("李四", 12);
  12. sm.add(s);
  13. sqlSession.commit();
  14. }
  15. @Test
  16. public void testUpdate(){
  17. Student s = new Student(3,"李四3", 3);
  18. sm.update(s);
  19. sqlSession.commit();
  20. }
  21. @Test
  22. public void testDelete(){
  23. sm.delete(5);
  24. sqlSession.commit();
  25. }
  26. @Test
  27. public void testFindById(){
  28. Student s = sm.findById(2);
  29. System.out.println(s);
  30. }
  31. @Test
  32. public void testFindAll(){
  33. List<Student> stuList = sm.findAll();
  34. for(Student s : stuList){
  35. System.out.println(s);
  36. }
  37. }
  38. @After
  39. public void tearDown() throws Exception {
  40. sqlSession.close();
  41. }
  42. }

MyBatis关系映射

对象间映射方式很多,以下方式都是采用的最佳实践,其余实现方式不予讲解,因为实际开发中不常用

一对一关系

新需求总是不停的出现,某天老板让我们在查询学生信息的时候同时显示出该学生的地址信息。于是我就想到了一对一关系映射。

为了演示一对一在MyBatis中的使用,我们需要修改一下表结构:

  1. 新增 t_address
  2. t_student 表添加 addressId 字段
  1. DROP TABLE IF EXISTS `t_address`;
  2. CREATE TABLE `t_address` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT,
  4. `sheng` varchar(20) DEFAULT NULL,
  5. `shi` varchar(20) DEFAULT NULL,
  6. `qu` varchar(20) DEFAULT NULL,
  7. PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  9. DROP TABLE IF EXISTS `t_student`;
  10. CREATE TABLE `t_student` (
  11. `id` int(11) NOT NULL AUTO_INCREMENT,
  12. `name` varchar(20) DEFAULT NULL,
  13. `age` int(11) DEFAULT NULL,
  14. `addressId` int(11) DEFAULT NULL
  15. PRIMARY KEY (`id`)
  16. ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

Student.java 添加 address 属性,并生成 getter()/setter() 方法, 同时更新 toString() 方法

  1. private Address address;
  2. public Address getAddress() {
  3. return address;
  4. }
  5. public void setAddress(Address address) {
  6. this.address = address;
  7. }

新增 Address.java

  1. public class Address {
  2. private int id;
  3. private String sheng;
  4. private String shi;
  5. private String qu;
  6. public int getId() {
  7. return id;
  8. }
  9. public void setId(int id) {
  10. this.id = id;
  11. }
  12. public String getSheng() {
  13. return sheng;
  14. }
  15. public void setSheng(String sheng) {
  16. this.sheng = sheng;
  17. }
  18. public String getShi() {
  19. return shi;
  20. }
  21. public void setShi(String shi) {
  22. this.shi = shi;
  23. }
  24. public String getQu() {
  25. return qu;
  26. }
  27. public void setQu(String qu) {
  28. this.qu = qu;
  29. }
  30. @Override
  31. public String toString() {
  32. return "Address [id=" + id + ", sheng=" + sheng + ", shi=" + shi
  33. + ", qu=" + qu + "]";
  34. }
  35. }

新增 AddressMapper.java

  1. import com.sue.demo.model.Address;
  2. public interface AddressMapper {
  3. public Address findById(Integer id);
  4. }

新增 AddressMapper.xml 文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.sue.demo.mappers.AddressMapper">
  6. <resultMap type="Address" id="AddressResult">
  7. <result property="id" column="id"/>
  8. <result property="sheng" column="sheng"/>
  9. <result property="shi" column="shi"/>
  10. <result property="qu" column="qu"/>
  11. </resultMap>
  12. <select id="findById" parameterType="Integer" resultType="Address">
  13. select * from t_address where id=#{id}
  14. </select>
  15. </mapper>

修改 StudentMapper.java,新增方法 findStudentWithAddress 用来查询学生和学生的地址信息

  1. public Student findStudentWithAddress(Integer id);

修改 StudentMapper.xml 文件:修改 StudentResult 并添加 findStudentWithAddress 查询

  1. <resultMap type="Student" id="StudentResult">
  2. <id property="id" column="id"/>
  3. <result property="name" column="name"/>
  4. <result property="age" column="age"/>
  5. <association property="address" column="addressId" select="com.sue.demo.mappers.AddressMapper.findById" />
  6. </resultMap>
  7. <select id="findByIdWithAddress" parameterType="Integer" resultMap="StudentResult">
  8. select * from t_student t1 ,t_address t2 where t1.addressId=t2.id and t1.id=#{id}
  9. </select>

测试案例

  1. @Test
  2. public void testFindByIdWithAddress(){
  3. Student student = sm.findByIdWithAddress(4);
  4. System.out.println(student);
  5. }

一对多关系

过了几天老板又提了一个新需求,需要根据年级查出该年级中的所有学生。

首先我们需要新增一张 t_grade 表,同时修改 t_student

  1. DROP TABLE IF EXISTS `t_grade`;
  2. CREATE TABLE `t_grade` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT,
  4. `gradeName` varchar(20) DEFAULT NULL,
  5. PRIMARY KEY (`id`)
  6. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  7. DROP TABLE IF EXISTS `t_student`;
  8. CREATE TABLE `t_student` (
  9. `id` int(11) NOT NULL AUTO_INCREMENT,
  10. `name` varchar(20) DEFAULT NULL,
  11. `age` int(11) DEFAULT NULL,
  12. `addressId` int(11) DEFAULT NULL,
  13. `gradeId` int(11) DEFAULT NULL,
  14. PRIMARY KEY (`id`)
  15. ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

新增 Grade.java

  1. import java.util.List;
  2. public class Grade {
  3. private int id;
  4. private String gradeName;
  5. private List<Student> students;
  6. public int getId() {
  7. return id;
  8. }
  9. public void setId(int id) {
  10. this.id = id;
  11. }
  12. public String getGradeName() {
  13. return gradeName;
  14. }
  15. public void setGradeName(String gradeName) {
  16. this.gradeName = gradeName;
  17. }
  18. public List<Student> getStudents() {
  19. return students;
  20. }
  21. public void setStudents(List<Student> students) {
  22. this.students = students;
  23. }
  24. @Override
  25. public String toString() {
  26. return "Grade [id=" + id + ", gradeName=" + gradeName + ", students="
  27. + students + "]";
  28. }
  29. }

新增 GradeMapper.java

  1. import com.sue.demo.model.Grade;
  2. public interface GradeMapper {
  3. public Grade findById(int id);
  4. }

新增 GradeMapper.xml 文件

  1. <!DOCTYPE mapper
  2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.sue.demo.mappers.GradeMapper">
  5. <resultMap type="Grade" id="GradeResult">
  6. <id property="id" column="id"/>
  7. <result property="gradeName" column="gradeName"/>
  8. <collection property="students" column="id" select="com.sue.demo.mappers.StudentMapper.findByGradeId"></collection>
  9. </resultMap>
  10. <select id="findById" parameterType="Integer" resultMap="GradeResult">
  11. select * from t_grade where id=#{id}
  12. </select>
  13. </mapper>

修改 StudentMapper.java,新增方法 findByGradeId 方法

  1. public Student findByGradeId(int id);

修改 StudentMapper.xml 文件,添加查询语句

  1. <select id="findByGradeId" parameterType="Integer" resultMap="StudentResult">
  2. select * from t_student where gradeId = #{gradeId}
  3. </select>

测试案例

  1. import org.apache.ibatis.session.SqlSession;
  2. import org.junit.After;
  3. import org.junit.Before;
  4. import org.junit.Test;
  5. import com.sue.demo.mappers.GradeMapper;
  6. import com.sue.demo.model.Grade;
  7. import com.sue.demo.util.SqlSessionFactoryUtil;
  8. public class GradeTest {
  9. private SqlSession sqlSession = null;
  10. private GradeMapper gm = null;
  11. @Before
  12. public void setUp() throws Exception {
  13. sqlSession = SqlSessionFactoryUtil.openSession();
  14. gm = sqlSession.getMapper(GradeMapper.class);
  15. }
  16. @Test
  17. public void testFindById() {
  18. Grade grade = gm.findById(1);
  19. System.out.println(grade);
  20. sqlSession.commit();
  21. }
  22. @After
  23. public void tearDown() throws Exception {
  24. sqlSession.close();
  25. }
  26. }

好不容易实现了新的需求,还没等喝口水的时间,老板又告诉你需要在查询学生信息的时候关联查出年级信息。我的天呢~ 能不能一口气说完。OK,不要抱怨了,开始吧!

Student.java 添加 grade 属性,并生成 getter()/setter() 方法, 同时更新 toString() 方法

  1. private Grade grade;
  2. public Grade getGrade() {
  3. return grade;
  4. }
  5. public void setGrade(Grade grade) {
  6. this.grade = grade;
  7. }

修改 StudentMapper.xml

  1. <resultMap type="Student" id="StudentResult">
  2. <id property="id" column="id"/>
  3. <result property="name" column="name"/>
  4. <result property="age" column="age"/>
  5. <association property="address" column="addressId" select="com.sue.demo.mappers.AddressMapper.findById" />
  6. <association property="grade" column="gradeId" select="com.sue.demo.mappers.GradeMapper.findById" />
  7. </resultMap>

测试案例 Student.java 中增加如下案例

  1. @Test
  2. public void testFindByIdWithGrade(){
  3. Student student = sm.findByIdWithAddress(4);
  4. System.out.println(student);
  5. }

如果你所有步骤都是按照文档来的话,此时应该会抛出 StackOverflowError 异常

  1. java.lang.StackOverflowError
  2. at java.util.ArrayList$Itr.<init>(ArrayList.java:820)
  3. at java.util.ArrayList$Itr.<init>(ArrayList.java:820)
  4. at java.util.ArrayList.iterator(ArrayList.java:814)
  5. at java.util.AbstractCollection.toString(AbstractCollection.java:450)
  6. at java.lang.String.valueOf(String.java:2847)
  7. at java.lang.StringBuilder.append(StringBuilder.java:128)
  8. at com.sue.demo.model.Grade.toString(Grade.java:38)
  9. at java.lang.String.valueOf(String.java:2847)
  10. at java.lang.StringBuilder.append(StringBuilder.java:128)
  11. at com.sue.demo.model.Student.toString(Student.java:71)
  12. at java.lang.String.valueOf(String.java:2847)
  13. at java.lang.StringBuilder.append(StringBuilder.java:128)
  14. ........

这是因为 Student.javaGrade.javatoString 方法 循环调用引起的,我们可以通过将 Grade.java 中的 Student 信息暂时不打印来解决这问题,Grade 中 toString 方法修改如下

  1. @Override
  2. public String toString() {
  3. return "Grade [id=" + id + ", gradeName=" + gradeName + "]";
  4. }

此时在运行单元测试,将会愉快的看到你期望的输出


Mybatis动态SQL

此节内容主要针对SQL(即xml),所以我们关注的对象为 XXXMapper.javaXXXMapper.xml
在开始之前,我们需要做如下准备:

  1. 复制 HelloWorld 项目并重命名为 MB_02
  2. 清空 StudentMapper.javaStudentMapper.xmlTest.java 代码
  3. 沿用以前的数据库
  1. MB_02
  2. --src
  3. --com.sue.demo
  4. --mappers
  5. --StudentMapper.java
  6. --StudentMapper.xml
  7. --model
  8. --Studnet.java
  9. --service
  10. --Test.java
  11. --util
  12. --SqlSessionFactoryUtil.java
  13. --lib
  14. --mysql-connector-java-3.1.12-bin.jar
  15. --mybatis-3.2.8.jar
  16. --jdbc.properties
  17. --mybatis-config.xml

if

StudentMapper.java 中新增查询方法 searchStudents

  1. import java.util.List;
  2. import java.util.Map;
  3. import com.sue.demo.model.Student;
  4. public interface StudentMapper {
  5. public List<Student> searchStudents(Map<String, Object> map);
  6. }

StudentMapper.xml 中添加相应实现

  1. <!DOCTYPE mapper
  2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.sue.demo.mappers.StudentMapper">
  5. <resultMap type="Student" id="StudentResult">
  6. <id property="id" column="id"/>
  7. <result property="name" column="name"/>
  8. <result property="age" column="age"/>
  9. </resultMap>
  10. <select id="searchStudents" parameterType="Map" resultMap="StudentResult">
  11. select * from t_student where 1=1
  12. <if test="name != null">
  13. and name like #{name}
  14. </if>
  15. <if test="age != null">
  16. and age = #{age}
  17. </if>
  18. </select>
  19. </mapper>

测试案例

  1. import java.util.HashMap;
  2. import java.util.List;
  3. import java.util.Map;
  4. import org.apache.ibatis.session.SqlSession;
  5. import org.junit.After;
  6. import org.junit.Before;
  7. import org.junit.Test;
  8. import com.sue.demo.mappers.StudentMapper;
  9. import com.sue.demo.model.Student;
  10. import com.sue.demo.util.SqlSessionFactoryUtil;
  11. public class StudentTest {
  12. private SqlSession sqlSession = null;
  13. private StudentMapper sm = null;
  14. @Before
  15. public void setUp() throws Exception {
  16. sqlSession = SqlSessionFactoryUtil.openSession();
  17. sm = sqlSession.getMapper(StudentMapper.class);
  18. }
  19. @Test
  20. public void testSearchStudents(){
  21. Map<String, Object> map = new HashMap<String, Object>();
  22. map.put("name", "%zhang%");
  23. map.put("age", 10);
  24. List<Student> students = sm.searchStudents(map);
  25. for(Student s : students){
  26. System.out.println(s);
  27. }
  28. }
  29. @After
  30. public void tearDown() throws Exception {
  31. sqlSession.close();
  32. }
  33. }

choose,when,otherwrise

假如有一个需求:页面有一个选择框,可以选择班级ID 学生名 ,如果不选择默认表示年龄,有一个输入框负责输入数据,通过这种方式来进行查询,那么后台就需要动态的拼接SQL,我们只需要将上一个栗子改造一下即可实现效果

StudentMapper.java 中新增查询方法 searchStudents1

  1. public List<Student> searchStudents1(Map<String, Object> map);

StudentMapper.xml 中新增对应查询

  1. <select id="searchStudents1" parameterType="Map" resultMap="StudentResult">
  2. select * from t_student
  3. <choose>
  4. <when test="searchBy == 'gradeId'">
  5. where gradeId = #{gradeId}
  6. </when>
  7. <when test="searchBy == 'name'">
  8. where name like #{name}
  9. </when>
  10. <otherwise>
  11. where age = #{age}
  12. </otherwise>
  13. </choose>
  14. </select>

测试案例

  1. @Test
  2. public void testSearchStudents1(){
  3. Map<String, Object> map = new HashMap<String, Object>();
  4. map.put("searchBy", "name");
  5. map.put("name", "%zhang%");
  6. map.put("age", 11);
  7. List<Student> students = sm.searchStudents1(map);
  8. for(Student s : students){
  9. System.out.println(s);
  10. }
  11. }

where

where 标签可以用 where 1=1 代替,可行但是不推荐,虽然写法简单,但是效率肯定是存在问题的
使用 where 标签的好处
1. 自动加上where
2. 如果where子句以and或者or开头,则自动删除第一个and或者or

同样还是修改第一个栗子

StudentMapper.java 中新增查询方法 searchStudents2

  1. public List<Student> searchStudents2(Map<String, Object> map);

StudentMapper.xml 中新增对应查询

  1. <select id="searchStudents2" parameterType="Map" resultMap="StudentResult">
  2. select * from t_student
  3. <where>
  4. <if test="name != null">
  5. and name like #{name}
  6. </if>
  7. <if test="age != null">
  8. and age = #{age}
  9. </if>
  10. </where>
  11. </select>

测试案例

  1. @Test
  2. public void testSearchStudents2(){
  3. Map<String, Object> map = new HashMap<String, Object>();
  4. map.put("name", "%zhang%");
  5. map.put("age", 10);
  6. List<Student> students = sm.searchStudents2(map);
  7. for(Student s : students){
  8. System.out.println(s);
  9. }
  10. }

trim

功能和 where 元素类似,提供了 前缀后缀 功能,相比更加灵活

同样还是修改第一个栗子

StudentMapper.java 中新增查询方法 searchStudents3

  1. public List<Student> searchStudents3(Map<String, Object> map);

StudentMapper.xml 中新增对应查询

  1. <select id="searchStudents3" parameterType="Map" resultMap="StudentResult">
  2. select * from t_student
  3. <trim prefix="where" prefixOverrides="and|or">
  4. <if test="name != null">
  5. and name like #{name}
  6. </if>
  7. <if test="age != null">
  8. and age = #{age}
  9. </if>
  10. </trim>
  11. </select>

测试案例

  1. @Test
  2. public void testSearchStudents3(){
  3. Map<String, Object> map = new HashMap<String, Object>();
  4. map.put("name", "%zhang%");
  5. map.put("age", 10);
  6. List<Student> students = sm.searchStudents3(map);
  7. for(Student s : students){
  8. System.out.println(s);
  9. }
  10. }

foreach

我们经常会写一些类似于 select id,age,name from t_student where gradeId in(1,2) 的语句,对于in的拼接,可以使用foreach元素

同样还是修改第一个栗子

StudentMapper.java 中新增查询方法 searchStudents4

  1. public List<Student> searchStudents4(Map<String, Object> map);

StudentMapper.xml 中新增对应查询

  1. <select id="searchStudents4" parameterType="Map" resultMap="StudentResult">
  2. select * from t_student
  3. <if test="gradeIds != null">
  4. <where>
  5. gradeId in
  6. <foreach collection="gradeIds" item="gradeId" open="(" separator="," close=")">
  7. #{gradeId}
  8. </foreach>
  9. </where>
  10. </if>
  11. </select>

测试案例

  1. @Test
  2. public void testSearchStudents4(){
  3. Map<String, Object> map = new HashMap<String, Object>();
  4. List<Integer> gradeIds = new ArrayList<Integer>();
  5. gradeIds.add(1);
  6. gradeIds.add(2);
  7. map.put("gradeIds", gradeIds);
  8. List<Student> students = sm.searchStudents4(map);
  9. for(Student s : students){
  10. System.out.println(s);
  11. }
  12. }

set

使用 set 的好处:
1. 自动加上 set
2. 自动删除最后一个逗号,

StudentMapper.java 中新增修改方法 updateStudent

  1. public int updateStudent(Student student);

StudentMapper.xml 中添加相应实现

  1. <update id="updateStudent" parameterType="Student">
  2. update t_student
  3. <set>
  4. <if test="name != null">
  5. name = #{name},
  6. </if>
  7. <if test="age != null">
  8. age = #{age},
  9. </if>
  10. </set>
  11. where id = #{id}
  12. </update>

测试案例

  1. @Test
  2. public void testUpdateStudents(){
  3. Student student = new Student();
  4. student.setId(1);
  5. student.setName("zhangsan-update");
  6. int i = sm.updateStudent(student);
  7. sqlSession.commit();
  8. if(i > 0) System.out.println("更新成功");
  9. }

MyBatis其他

掌握以上知识点,开发应该不会有太大的问题。本章主要讲解一些MyBatis的边角知识,平时使用频率不高,了解会用即可

CLOB 和 BLOB类型处理

  1. CLOB类型:大文本类型,可以存储大篇幅文本,使用频率一般
  2. BLOB类型:二进制存储,可以存储电影,音乐,图片等内容,使用频率低

新建 t_other

  1. DROP TABLE IF EXISTS `t_other`;
  2. CREATE TABLE `t_other` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT,
  4. `pic` longblob,
  5. `remark` longtext,
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

新建 Other.java

  1. import java.util.Arrays;
  2. public class Other {
  3. private int id;
  4. private byte[] pic;
  5. private String remark;
  6. public int getId() {
  7. return id;
  8. }
  9. public void setId(int id) {
  10. this.id = id;
  11. }
  12. public byte[] getPic() {
  13. return pic;
  14. }
  15. public void setPic(byte[] pic) {
  16. this.pic = pic;
  17. }
  18. public String getRemark() {
  19. return remark;
  20. }
  21. public void setRemark(String remark) {
  22. this.remark = remark;
  23. }
  24. @Override
  25. public String toString() {
  26. return "Other [id=" + id + ", remark=" + remark + "]";
  27. }
  28. }

新建 OtherMapper.java

  1. import com.sue.demo.model.Other;
  2. public interface OtherMapper {
  3. public int insertOther(Other other);
  4. public Other getOtherById(int id);
  5. }

新建 OtherMapper.xml

  1. <!DOCTYPE mapper
  2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.sue.demo.mappers.OtherMapper">
  5. <insert id="insertOther" parameterType="Other">
  6. insert into t_other values(null,#{pic},#{remark})
  7. </insert>
  8. <select id="getOtherById" parameterType="int" resultType="Other">
  9. select * from t_other where id = #{id}
  10. </select>
  11. </mapper>

新增测试案例 OtherTest.java

  1. import java.io.File;
  2. import java.io.FileOutputStream;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import org.apache.ibatis.io.Resources;
  6. import org.apache.ibatis.session.SqlSession;
  7. import org.junit.After;
  8. import org.junit.Before;
  9. import org.junit.Test;
  10. import com.sue.demo.mappers.OtherMapper;
  11. import com.sue.demo.model.Other;
  12. import com.sue.demo.util.SqlSessionFactoryUtil;
  13. public class OtherTest {
  14. private SqlSession sqlSession = null;
  15. private OtherMapper om = null;
  16. @Before
  17. public void setUp() throws Exception {
  18. sqlSession = SqlSessionFactoryUtil.openSession();
  19. om = sqlSession.getMapper(OtherMapper.class);
  20. }
  21. @Test
  22. public void testInsertOther(){
  23. Other other = new Other();
  24. other.setRemark("这是一篇文章,很长很长。");
  25. byte[] pic = null;
  26. try{
  27. InputStream is = Resources.getResourceAsStream("longze.jpg");
  28. pic = new byte[is.available()];
  29. is.read(pic);
  30. is.close();
  31. }catch(Exception e){
  32. e.printStackTrace();
  33. }
  34. other.setPic(pic);
  35. int i = om.insertOther(other);
  36. sqlSession.commit();
  37. if(i > 0) System.out.println("插入成功");
  38. }
  39. @Test
  40. public void testGetOtherById(){
  41. Other other = om.getOtherById(2);
  42. byte[] pic = other.getPic();
  43. try{
  44. File file = new File("temp.jpg");
  45. OutputStream os = new FileOutputStream(file);
  46. os.write(pic);
  47. os.close();
  48. }catch(Exception e){
  49. e.printStackTrace();
  50. }
  51. }
  52. @After
  53. public void tearDown() throws Exception {
  54. sqlSession.close();
  55. }
  56. }

MyBatis分页

逻辑分页

比如数据库有100条数据,我们需要每页显示10条,将100条一次性加载到内存,再取10条进行分页展示,数据量一大,性能明显低

StudentMapper.java 中新增查询方法 findStudents

  1. public List<Student> findStudents(RowBounds rowBounds);

StudentMapper.xml 中新增查询语句

  1. <select id="findStudents" resultMap="StudentResult">
  2. select * from t_student
  3. </select>

StudentTest.java 中新增测试案例

  1. @Test
  2. public void testFindStudents(){
  3. int offset = 0;
  4. int limit = 2;
  5. RowBounds rowBounds = new RowBounds(offset, limit);
  6. List<Student> students = sm.findStudents(rowBounds);
  7. for(Student s : students){
  8. System.out.println(s);
  9. }
  10. }

物理分页

直接从数据库查询出你需要的数据,应用多,效率高

StudentMapper.java 中新增查询方法 findStudents1

  1. public List<Student> findStudents1(Map<String, Object> map);

StudentMapper.xml 中新增查询语句

  1. <select id="findStudents1" parameterType="Map" resultMap="StudentResult">
  2. select * from t_student
  3. <if test="start != null and size != null">
  4. limit #{start}, #{size}
  5. </if>
  6. </select>

StudentTest.java 中新增测试案例

  1. @Test
  2. public void testFindStudents1(){
  3. Map<String, Object> map = new HashMap<String, Object>();
  4. map.put("start", 0);
  5. map.put("size", 2);
  6. List<Student> students = sm.findStudents1(map);
  7. for(Student s : students){
  8. System.out.println(s);
  9. }
  10. }

MyBatis缓存

默认情况下,MyBatis 启用一级缓存,即同一个 SqlSession 接口对象调用了相同的 SELECT 语句,则直接会从缓存中返回结果,而不是再查询一次数据库

开发者可以自己配置二级缓存,二级缓存是全局的

默认情况下,SELECT 是使用缓存的,insert update delete 是不使用缓存的

启用缓存的话,需要先配置缓存,配置在Mapper文件的 <mapper> 元素下

  1. <!--
  2. 1,size:表示缓存cache中能容纳的最大元素数。默认是1024;
  3. 2,flushInterval:定义缓存刷新周期,以毫秒计;
  4. 3,eviction:定义缓存的移除机制;默认是LRU(least recently userd,最近最少使用),还有FIFO(first in first out,先进先出)
  5. 4,readOnly:默认值是false,假如是true的话,缓存只能读。
  6. -->
  7. <cache size="1024" flushInterval="60000" eviction="LRU" readOnly="false"/>

启用缓存的话,需要在具体的 select insert update 中开启

  1. <select id="findStudents" resultMap="StudentResult" useCache="true">
  2. select * from t_student
  3. </select>
  4. <update id="updateStudent" parameterType="Student" flushCache="true">
  5. update t_student
  6. <set>
  7. <if test="name != null">
  8. name = #{name},
  9. </if>
  10. <if test="age != null">
  11. age = #{age},
  12. </if>
  13. </set>
  14. where id = #{id}
  15. </update>

实际项目开发中,很少使用,一般缓存都是通过第三方组件解决


注解配置SQL映射器

本节内容可添加装逼属性,请选择性观看,MyBatis该特性可以省略 XXMapper.xml 文件的编写,带来开发上的体验(纯属装逼),但同时带来的弊端是不利于SQL的维护。实际开发中几乎没有这么使用的,除非项目经理脑子疼或者被驴踢过。

基本映射语句

这节将会带领大家实现一个基于注解的 案例,首先我们可以复制 MB_02 项目,并重命名为 MB_03 ,同时删除无用的类,最终项目结构和代码清单如下:

  1. MB_03
  2. --src
  3. --com.sue.demo
  4. --mappers
  5. --StudentMapper.java
  6. --model
  7. --Studnet.java
  8. --service
  9. --StudentTest.java
  10. --util
  11. --SqlSessionFactoryUtil.java
  12. --lib
  13. --mysql-connector-java-3.1.12-bin.jar
  14. --mybatis-3.2.8.jar
  15. --jdbc.properties
  16. --mybatis-config.xml

Student.java

  1. public class Student {
  2. private int id;
  3. private String name;
  4. private int age;
  5. public Student() {
  6. super();
  7. }
  8. public Student(int id, String name, int age) {
  9. super();
  10. this.id = id;
  11. this.name = name;
  12. this.age = age;
  13. }
  14. public Student(String name, int age) {
  15. super();
  16. this.name = name;
  17. this.age = age;
  18. }
  19. public int getId() {
  20. return id;
  21. }
  22. public void setId(int id) {
  23. this.id = id;
  24. }
  25. public String getName() {
  26. return name;
  27. }
  28. public void setName(String name) {
  29. this.name = name;
  30. }
  31. public int getAge() {
  32. return age;
  33. }
  34. public void setAge(int age) {
  35. this.age = age;
  36. }
  37. @Override
  38. public String toString() {
  39. return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
  40. }
  41. }

StudentMapper.java

  1. import java.util.List;
  2. import com.sue.demo.model.Student;
  3. public interface StudentMapper {
  4. public int updateStudent(Student student);
  5. public int insertStudent(Student student);
  6. public Student getStudentById(int id);
  7. public int deleteStudentById(int id);
  8. }

SqlSessionFactoryUtil.java

  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import org.apache.ibatis.io.Resources;
  4. import org.apache.ibatis.session.SqlSession;
  5. import org.apache.ibatis.session.SqlSessionFactory;
  6. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  7. public class SqlSessionFactoryUtil {
  8. public static SqlSessionFactory sqlSessionFactory;
  9. public static SqlSessionFactory getSqlSessionFactory(){
  10. if(sqlSessionFactory == null){
  11. InputStream is = null;
  12. try {
  13. is = Resources.getResourceAsStream("mybatis-config.xml");
  14. sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. return sqlSessionFactory;
  20. }
  21. public static SqlSession openSession(){
  22. return getSqlSessionFactory().openSession();
  23. }
  24. }

StudentTest.java

  1. import org.apache.ibatis.session.SqlSession;
  2. import org.junit.After;
  3. import org.junit.Before;
  4. import org.junit.Test;
  5. import com.sue.demo.mappers.StudentMapper;
  6. import com.sue.demo.util.SqlSessionFactoryUtil;
  7. public class StudentTest {
  8. private SqlSession sqlSession = null;
  9. private StudentMapper sm = null;
  10. @Before
  11. public void setUp() throws Exception {
  12. sqlSession = SqlSessionFactoryUtil.openSession();
  13. sm = sqlSession.getMapper(StudentMapper.class);
  14. }
  15. @Test
  16. public void testSearchStudents(){
  17. }
  18. @After
  19. public void tearDown() throws Exception {
  20. sqlSession.close();
  21. }
  22. }

做好以上准备,我们就可以愉快的开始装逼旅程了.

@INSERT

StudentMapper.java 中为 insertStudent 方法添加 @Insert 注解

  1. @Insert("insert into t_student values(null, #{name}, #{age})")
  2. public int insertStudent(Student student);

测试案例

  1. @Test
  2. public void testInsertStudent(){
  3. Student student = new Student("xiaoming", 20);
  4. sm.insertStudent(student);
  5. sqlSession.commit();
  6. }

@UPDATE

StudentMapper.java 中为 updateStudent 方法添加 @Update 注解

  1. @Update("update t_student set name=#{name}, age=#{age} where id=#{id}")
  2. public int updateStudent(Student student);

测试案例

  1. @Test
  2. public void testUpdateStudent(){
  3. Student student = new Student("xiaoming-up", 21);
  4. student.setId(4);
  5. sm.updateStudent(student);
  6. sqlSession.commit();
  7. }

@DELETE

StudentMapper.java 中为 deleteStudentById 方法添加 @Delete 注解

  1. @Delete("delete from t_student where id=#{id}")
  2. public int deleteStudentById(int id);

测试案例

  1. @Test
  2. public void testDeleteStudentById(){
  3. sm.deleteStudentById(4);
  4. sqlSession.commit();
  5. }

@SELECT

StudentMapper.java 中为 getStudentById 方法添加 @Select 注解

  1. @Select("select * from t_student where id=#{id}")
  2. public Student getStudentById(int id);

测试案例

  1. @Test
  2. public void testGetStudentById(){
  3. Student student = sm.getStudentById(3);
  4. System.out.println(student);
  5. }

结果集映射

了解了基本的 操作后,我们再来看一个结果集映射。

在使用 xml 进行sql定义的时候,我们的 resultMap 属性对应着一个自定义的 <resultMap> 集合,在注解的方式中,我们需要使用到 @Results@Result 注解来完成这种关系的映射

StudentMapper.java 中为 deleteStudentById 方法添加 @Delete 注解

  1. @Delete("delete from t_student where id=#{id}")
  2. public int deleteStudentById(int id);

测试案例

  1. @Test
  2. public void testDeleteStudentById(){
  3. sm.deleteStudentById(4);
  4. sqlSession.commit();
  5. }

StudentMapper.java 中为 findStudents 方法添加 @Select @Results @Result 注解

  1. @Select("select * from t_student")
  2. @Results
  3. (
  4. {
  5. @Result(id=true, column="id", property="id"),
  6. @Result(column="name", property="name"),
  7. @Result(column="age", property="age"),
  8. }
  9. )
  10. public List<Student> findStudents();

测试案例

  1. @Test
  2. public void testFindStudents(){
  3. List<Student> students = sm.findStudents();
  4. for(Student s : students){
  5. System.out.println(s);
  6. }
  7. }

关系映射

一对一关系

MyBatis关系映射 > 一对一关系 这一讲中,将 Address.javaAddressMapper.java 复制到 MB_03 项目中

Student.java 中添加 Address 属性 ,生成 getter/setter 方法,同时更新 toString() 方法

  1. private Address address;
  2. public Address getAddress() {
  3. return address;
  4. }
  5. public void setAddress(Address address) {
  6. this.address = address;
  7. }

StudentMapper.java 中新增 selectStudentWithAddress 方法,同时添加 @Select @Results @Result @One 注解

  1. @Select("select * from t_student where id=#{id}")
  2. @Results
  3. (
  4. {
  5. @Result(id=true, column="id", property="id"),
  6. @Result(column="name", property="name"),
  7. @Result(column="age", property="age"),
  8. @Result(column="addressId", property="address", one=@One(select="com.sue.demo.mappers.AddressMapper.findByid"))
  9. }
  10. )
  11. public Student selectStudentWithAddress(int id);

AddressMapper.java 中新增 findByid 方法,同时添加 @Select 注解

  1. @Select("select * from t_address where id=#{id}")
  2. public Address findByid(int id);

测试案例

  1. @Test
  2. public void testSelectStudentWithAddress(){
  3. Student student = sm.selectStudentWithAddress(3);
  4. System.out.println(student);
  5. }

一对多关系

MyBatis关系映射 > 一对一关系 这一讲中,将 Grade.javaGradeMapper.java 复制到 MB_03 项目中

注意 Grade.java 需生成完整的 getter/setter 方法并 toString 所有属性

Student.java 中添加 Grade 属性 ,生成 getter/setter 方法,同时更新 toString() 方法[请不要输出 grade 属性]

  1. private Grade grade;
  2. public Grade getGrade() {
  3. return grade;
  4. }
  5. public void setGrade(Grade grade) {
  6. this.grade = grade;
  7. }
  8. @Override
  9. public String toString() {
  10. return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
  11. }

GradeMapper.java 中为 findById 方法添加 @Select @Results @Result @Many 注解

  1. @Select("select * from t_grade where id=#{id}")
  2. @Results
  3. (
  4. {
  5. @Result(id=true, column="id", property="id"),
  6. @Result(column="gradeName", property="gradeName"),
  7. @Result(column="id", property="students", many=@Many(select="com.sue.demo.mappers.StudentMapper.selectStudentByGradeId"))
  8. }
  9. )
  10. public Grade findById(int id);

StudentMapper.java 中新增 selectStudentByGradeId 方法,同时添加 @Select @Results @Result @One 注解

  1. @Select("select * from t_student where gradeId=#{id}")
  2. @Results
  3. (
  4. {
  5. @Result(id=true, column="id", property="id"),
  6. @Result(column="name", property="name"),
  7. @Result(column="age", property="age"),
  8. @Result(column="addressId", property="address", one=@One(select="com.sue.demo.mappers.AddressMapper.findByid"))
  9. }
  10. )
  11. public Student selectStudentByGradeId(int id);

测试案例,新建 GradeTest.java

  1. import org.apache.ibatis.session.SqlSession;
  2. import org.junit.After;
  3. import org.junit.Before;
  4. import org.junit.Test;
  5. import com.sue.demo.mappers.GradeMapper;
  6. import com.sue.demo.model.Grade;
  7. import com.sue.demo.util.SqlSessionFactoryUtil;
  8. public class GradeTest {
  9. private SqlSession sqlSession = null;
  10. private GradeMapper gm = null;
  11. @Before
  12. public void setUp() throws Exception {
  13. sqlSession = SqlSessionFactoryUtil.openSession();
  14. gm = sqlSession.getMapper(GradeMapper.class);
  15. }
  16. @Test
  17. public void testfindById(){
  18. Grade grade = gm.findById(1);
  19. System.out.println(grade);
  20. }
  21. @After
  22. public void tearDown() throws Exception {
  23. sqlSession.close();
  24. }
  25. }

换个思路,如果我们想通过查询学生带出年级信息,又该怎么做呢?这也是在开发中很常用的反向的对应关系,下面我们就做一个实例来看一下应该怎么实现

基于上述代码,在 StudentMapper.java 中新增 selectStudentWithAddressAndGrade 方法,同时添加 @Select @Results @Result @One 注解

  1. @Select("select * from t_student where id=#{id}")
  2. @Results
  3. (
  4. {
  5. @Result(id=true, column="id", property="id"),
  6. @Result(column="name", property="name"),
  7. @Result(column="age", property="age"),
  8. @Result(column="addressId", property="address", one=@One(select="com.sue.demo.mappers.AddressMapper.findByid")),
  9. @Result(column="gradeId", property="grade", one=@One(select="com.sue.demo.mappers.GradeMapper.findById"))
  10. }
  11. )
  12. public Student selectStudentWithAddressAndGrade(int id);

更新 Student.javatoString() 方法,输出所有字段,为了防止内存溢出,我们还需要将 Grade.javatoString() 方法中的 student 属性去掉,不做输出。

测试案例

  1. @Test
  2. public void testSelectStudentWithAddressAndGrade(){
  3. Student student = sm.selectStudentWithAddressAndGrade(1);
  4. System.out.println(student);
  5. }

动态SQL

该章作为了解即可,实际开发中还是用 xml 的方式进行开发,在开发前我们先在 MB_03 中新建一个演示类 StudentModel.java ,一个动态sql提供类 StudentDynamicSqlProvider.java 用来构建动态sql,一个Mapper类 StudentModelMapper.java,和一个测试类 StudentModelTest.java ,清单如下:

StudentModel.java

  1. package com.sue.demo.model;
  2. public class StudentModel {
  3. private int id;
  4. private String name;
  5. private Integer age;
  6. public StudentModel() {
  7. }
  8. public StudentModel(String name, int age) {
  9. this.name = name;
  10. this.age = age;
  11. }
  12. public int getId() {
  13. return id;
  14. }
  15. public void setId(int id) {
  16. this.id = id;
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. public Integer getAge() {
  25. return age;
  26. }
  27. public void setAge(Integer age) {
  28. this.age = age;
  29. }
  30. @Override
  31. public String toString() {
  32. return "StudentModel [id=" + id + ", name=" + name + ", age=" + age
  33. + "]";
  34. }
  35. }

StudentModelMapper.java

  1. package com.sue.demo.mappers;
  2. import com.sue.demo.model.StudentModel;
  3. public interface StudentModelMapper {
  4. public int insertStudentModel(StudentModel studentModel);
  5. public int updateStudentModel(StudentModel studentModel);
  6. public int deleteStudentModelById(int id);
  7. public StudentModel getStudentModelById(int id);
  8. }

StudentDynamicSqlProvider.java

  1. 空:下面会慢慢补充

StudentModelTest.java

  1. package com.sue.demo.service;
  2. import org.apache.ibatis.session.SqlSession;
  3. import org.junit.After;
  4. import org.junit.Before;
  5. import org.junit.Test;
  6. import com.sue.demo.mappers.StudentModelMapper;
  7. import com.sue.demo.model.StudentModel;
  8. import com.sue.demo.util.SqlSessionFactoryUtil;
  9. public class StudentModelTest {
  10. private SqlSession sqlSession = null;
  11. private StudentModelMapper sm = null;
  12. @Before
  13. public void setUp() throws Exception {
  14. sqlSession = SqlSessionFactoryUtil.openSession();
  15. sm = sqlSession.getMapper(StudentModelMapper.class);
  16. }
  17. @Test
  18. public void testInsertStudentModel(){
  19. }
  20. @Test
  21. public void testUpdateStudent(){
  22. }
  23. @Test
  24. public void testDeleteStudentById(){
  25. }
  26. @Test
  27. public void testGetStudentById(){
  28. }
  29. @After
  30. public void tearDown() throws Exception {
  31. sqlSession.close();
  32. }
  33. }

@InsertProvider

StudentDynamicSqlProvider.java 中新建方法 insertStudent

  1. public String insertStudentModel(final StudentModel studentModel){
  2. return new SQL(){
  3. {
  4. INSERT_INTO("t_student");
  5. if(studentModel.getName() != null){
  6. VALUES("name", "#{name}");
  7. }
  8. if(studentModel.getAge() != null){
  9. VALUES("age", "#{age}");
  10. }
  11. }
  12. }.toString();
  13. }

StudentModelMapper.javainsertStudent 方法上添加注解 @InsertProvider

  1. @InsertProvider(type=StudentDynamicSqlProvider.class, method="insertStudentModel")
  2. public int insertStudentModel(StudentModel studentModel);

补充测试案例

  1. @Test
  2. public void testInsertStudentModel(){
  3. StudentModel studentModel = new StudentModel("insert", 18);
  4. sm.insertStudentModel(studentModel);
  5. sqlSession.commit();
  6. }

@UpdateProvider

StudentDynamicSqlProvider.java 中新建方法 insertStudent

  1. public String updateStudentModel(final StudentModel studentModel){
  2. return new SQL(){
  3. {
  4. UPDATE("t_student");
  5. if(studentModel.getName() != null){
  6. SET("name=#{name}");
  7. }
  8. if(studentModel.getAge() !=null){
  9. SET("age=#{age}");
  10. }
  11. WHERE("id=#{id}");
  12. }
  13. }.toString();
  14. }

StudentModelMapper.javaupdateStudentModel 方法上添加注解 @UpdateProvider

  1. @UpdateProvider(type=StudentDynamicSqlProvider.class, method="updateStudentModel")
  2. public int updateStudentModel(StudentModel studentModel);

补充测试案例

  1. @Test
  2. public void testUpdateStudent(){
  3. StudentModel studentModel = new StudentModel("insert-update", 20);
  4. studentModel.setId(5);
  5. sm.updateStudentModel(studentModel);
  6. sqlSession.commit();
  7. }

@DeleteProvider

StudentDynamicSqlProvider.java 中新建方法 insertStudent

  1. public String deleteStudentModel(){
  2. return new SQL(){
  3. {
  4. DELETE_FROM("t_student");
  5. WHERE("id=#{id}");
  6. }
  7. }.toString();
  8. }

StudentModelMapper.javadeleteStudentModelById 方法上添加注解 @DeleteProvider

  1. @DeleteProvider(type=StudentDynamicSqlProvider.class, method="deleteStudentModel")
  2. public int deleteStudentModelById(int id);

补充测试案例

  1. @Test
  2. public void testDeleteStudentById(){
  3. sm.deleteStudentModelById(5);
  4. sqlSession.commit();
  5. }

@SelectProvider

StudentDynamicSqlProvider.java 中新建方法 getStudentModelById

  1. public String getStudentModelById(){
  2. return new SQL(){
  3. {
  4. SELECT("*");
  5. FROM("t_student");
  6. WHERE("id=#{id}");
  7. }
  8. }.toString();
  9. }

StudentModelMapper.javagetStudentModelById 方法上添加注解 @SelectProvider

  1. @SelectProvider(type=StudentDynamicSqlProvider.class, method="getStudentModelById")
  2. public StudentModel getStudentModelById(int id);

补充测试案例

  1. @Test
  2. public void testGetStudentById(){
  3. StudentModel studentModel = sm.getStudentModelById(1);
  4. System.out.println(studentModel);
  5. }

稍复杂操作

做完基本的 操作后,我们再来一个稍微复杂一点的

StudentDynamicSqlProvider.java 中新建方法 findStudentsByCondation

  1. public String findStudentsByCondation(final Map<String, Object> param){
  2. return new SQL(){
  3. {
  4. SELECT("*");
  5. FROM("t_student");
  6. StringBuffer sb = new StringBuffer();
  7. if(param.get("name") != null){
  8. sb.append(" and name like '" + param.get("name") + "'");
  9. }
  10. if(param.get("age") != null){
  11. sb.append(" and age = " + param.get("age"));
  12. }
  13. WHERE(sb.toString().replaceFirst("and", ""));
  14. }
  15. }.toString();
  16. }

StudentModelMapper.javafindStudentsByCondation 方法上添加注解 @SelectProvider

  1. @SelectProvider(type=StudentDynamicSqlProvider.class, method="findStudentsByCondation")
  2. public List<StudentModel> findStudentsByCondation(Map<String, Object> param);

补充测试案例

  1. @Test
  2. public void findStudentsByCondation(){
  3. Map<String,Object> param = new HashMap<String,Object>();
  4. param.put("name", "%zhang%");
  5. param.put("age", 10);
  6. List<StudentModel> studentModels = sm.findStudentsByCondation(param);
  7. System.out.println(studentModels);
  8. }

MyBatis与Spring,SpringMVC整合

该节内容请参照 MB_04 ,因网上教程太多,不再笔述

Spring与SpringMVC整合

Spring与MyBatis整合


添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注