Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

    关系型数据库和SQL是经受时间考验和验证的数据存储机制。和其它的ORM 框架如Hibernate不同,MyBatis鼓舞开发人员能够直接使用数据库,而不是将其对开发人员隐藏,由于这样能够充分发挥数据库server所提供的SQL语句的巨大威力。与此同一时候,MyBaits消除了书写大量冗余代码的痛苦,它使使用SQL更easy。

    在代码里直接嵌套SQL语句是非常差的编码实践,而且维护起来困难。MyBaits使用了映射器配置文件或注解来配置SQL语句。在本章中,我们会看到详细如何使用映射器配置文件来配置映射SQL语句。

 

本章将涵盖下面话题:

  • 映射器配置文件映射器接口
  • 映射语句

           ž配置INSERT, UPDATE, DELETE,and SELECT语句

  • 结果映射ResultMaps

           ž简单 ResultMaps

           ž使用内嵌select语句子查询的一对一映射

           ž使用内嵌的结果集查询的一对一映射

           ž使用内嵌select语句子查询的一对多映射

           ž使用内嵌的结果集查询的一对一映射

  • 动态SQL语句

           žIf 条件

           žchoose (when, otherwise) 条件

           žtrim (where, set) 条件

           žforeach 循环

  • MyBatis 菜谱

3.1 映射器配置文件和映射器接口

    在前几章中,我们已经看见了一些在映射器配置文件里配置主要的映射语句。以及如何使用SqlSession对象调用它们的样例。

    如今让我们看一下在com.mybatis3.mappers包中的StudentMapper.xml 配置文件内,是怎样配置 id 为”findStudentById”的SQL语句的,代码例如以下:

<?

xml version="1.0" encoding="utf-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mybatis3.mappers.StudentMapper"> <select id="findStudentById" parameterType="int" resultType="Student"> select stud_id as studId, name, email, dob from Students where stud_id=#{studId} </select> </mapper>


我们能够通过下列代码调用findStudentById映射的SQL语句:

public Student findStudentById(Integer studId)
{
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    try
    {
        Student student =
            sqlSession.selectOne("com.mybatis3.mappers.StudentMapper.
                                 findStudentById", studId);
        return student;
    }
    finally
    {
        sqlSession.close();
    }
}

    我们能够通过字符串(字符串形式为:映射器配置文件所在的包名namespace + 在文件内定义的语句id,如上,即包名com.mybatis3.mappers.StudentMapper 和语句idfindStudentById 组成)调用映射的SQL语句。可是这样的方式easy出错。你须要检查映射器配置文件里的定义。以保证你的输入參数类型和结果返回类型是有效的。

    MyBatis通过使用映射器Mapper接口提供了更好的调用映射语句的方法。

一旦我们通过映射器配置文件配置了映射语句,我们能够创建一个全然相应的一个映射器接口。接口名跟配置文件名称同样,接口所在包名也跟配置文件所在包名全然一样(如StudentMapper.xml所在的包名是com.mybatis3.mappers,相应的接口名就是com.mybatis3.mappers.StudentMapper.java)。映射器接口中的方法签名也跟映射器配置文件里全然相应:方法名为配置文件里id值。方法參数类型为parameterType相应值;方法返回值类型为returnType相应值。

 

    对于上述的 StudentMapper.xml 文件,我们能够创建一个映射器接口StudentMapper.java 例如以下:

package com.mybatis3.mappers;
public interface StudentMapper
{
    Student findStudentById(Integer id);
}

    在StudentMapper.xml 映射器配置文件里,其名空间namespace 应该跟StudentMapper接口的全然限定名保持一致。

另外。StudentMapper.xml中语句id,parameterType,returnType应该分别和StudentMapper接口中的方法名,參数类型,返回值相相应。

 

    使用映射器接口我们能够以类型安全的形式调用调用映射语句。例如以下所看到的:

	public Student findStudentById(Integer studId)
{
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    try
    {
        StudentMapper studentMapper =
            sqlSession.getMapper(StudentMapper.class);
        return studentMapper.findStudentById(studId);
    }
    finally
    {
        sqlSession.close();
    }
}

3.2 映射语句

MyBatis提供了多种元素来配置不同类型的语句,如SELECT,INSERT。UPDATE,DELETE。接下来让我们看看怎样详细配置映射语句。

3.2.1 INSERT语句

一个INSERT SQL语句能够在<insert>元素在映射器XML配置文件里配置。例如以下所看到的:

<insert id="insertStudent" parameterType="Student">
    INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL, PHONE)
        VALUES(#{studId},#{name},#{email},#{phone})
</insert>

    这里我们使用一个ID insertStudent。能够在名空间com.mybatis3.mappers.StudentMapper.insertStudent中唯一标识。parameterType属性应该是一个全然限定类名或者是一个类型别名(alias)。

 

我们能够例如以下调用这个语句:
int count =sqlSession.insert("com.mybatis3.mappers.StudentMapper.insertStudent", student);

sqlSession.insert()方法返回运行INSERT语句后所影响的行数。

假设不使用名空间(namespace)和语句id来调用映射语句,你能够通过创建一个映射器Mapper接口,并以类型安全的方式调用方法,例如以下所看到的:

package com.mybatis3.mappers;
public interface StudentMapper
{
    int insertStudent(Student student);
}

你能够例如以下调用 insertStudent 映射语句:

StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
int count = mapper.insertStudent(student);

[自己主动生成主键]

在上述的INSERT语句中,我们为能够自己主动生成(auto-generated)主键的列STUD_ID插入值。

我们能够使用useGeneratedKeyskeyProperty属性让数据库生成 auto_increment列的值。并将生成的值设置到当中一个输入对象属性内,例如以下所看到的:

<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true"
         keyProperty="studId">
    INSERT INTO STUDENTS(NAME, EMAIL, PHONE) 
    VALUES(#{name},#{email},#{phone})
</insert>

这里 STUD_ID列值将会被MySQL 数据库自己主动生成。而且生成的值会被设置到student对象的studId属性上。

StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
mapper.insertStudent(student);

如今能够例如以下获取插入的STUDENT 记录的STUD_ID的值:

int studentId = student.getStudId();

有些数据库如Oracle并不支持 AUTO_INCREMENT 列,其使用序列(SEQUENCE)来生成主键值。

如果我们有一个名为 STUD_ID_SEQ 的序列来生成SUTD_ID主键值。使用例如以下代码来生成主键:

<insert id="insertStudent" parameterType="Student">
    <selectKey keyProperty="studId" resultType="int" order="BEFORE">
        SELECT ELEARNING.STUD_ID_SEQ.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL, PHONE)
        VALUES(#{studId},#{name},#{email},#{phone})
</insert>

    这里我们使用了<selectKey>子元素来生成主键值,并将值保存到Student对象的studId属性上。 属性order=“before”表示MyBatis将取得序列的下一个值作为主键值。而且在运行INSERTSQL语句之前将值设置到studId属性上。

    我们也能够在获取序列的下一个值时,使用触发器(trigger)来设置主键值。而且在运行INSERT SQL语句之前将值设置到主键列上。假设你採取这种方式,则相应的INSERT映射语句例如以下所看到的:

<insert id="insertStudent" parameterType="Student">
    INSERT INTO STUDENTS(NAME,EMAIL, PHONE)
        VALUES(#{name},#{email},#{phone})
    <selectKey keyProperty="studId" resultType="int" order="AFTER">
        SELECT ELEARNING.STUD_ID_SEQ.CURRVAL FROM DUAL
    </selectKey>
</insert>

3.2.2 UPDATE语句

一个UPDATE SQL语句能够在<update>元素在映射器XML配置文件里配置,例如以下所看到的:

<update id="updateStudent" parameterType="Student">
    UPDATE STUDENTS SET NAME=#{name}, EMAIL=#{email}, PHONE=#{phone}
    WHERE STUD_ID=#{studId}
</update>

我们能够例如以下调用此语句:

int noOfRowsUpdated =
sqlSession.update("com.mybatis3.mappers.StudentMapper.updateStudent", student);

sqlSession.update() 方法返回运行UPDATE语句之后影响的行数。

假设不使用名空间(namespace)和语句id来调用映射语句,你能够通过创建一个映射器Mapper接口。并以类型安全的方式调用方法。例如以下所看到的:

package com.mybatis3.mappers;
public interface StudentMapper
{
    int updateStudent(Student student);
}

你能够使用映射器Mapper接口来调用 updateStudent语句,例如以下所看到的:

StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
int noOfRowsUpdated = mapper.updateStudent(student);

3.2.3 DELETE 语句

一个UPDATE SQL语句能够在<update>元素在映射器XML配置文件里配置。例如以下所看到的:

<delete id="deleteStudent" parameterType="int">
   DELETE FROM STUDENTS WHERE STUD_ID=#{studId}
</delete>

我们能够例如以下调用此语句:

int studId = 1;
int noOfRowsDeleted =
    sqlSession.delete("com.mybatis3.mappers.StudentMapper.deleteStudent", studId);

sqlSession.delete()方法返回delete语句运行后影响的行数。

 

假设不使用名空间(namespace)和语句id来调用映射语句。你能够通过创建一个映射器Mapper接口,并以类型安全的方式调用方法,例如以下所看到的:

package com.mybatis3.mappers;
public interface StudentMapper
{
    int deleteStudent(int studId);
}

你能够使用映射器Mapper接口来调用 updateStudent语句。例如以下所看到的:

StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
int noOfRowsDeleted = mapper.deleteStudent(studId);

3.2.4 SELECT语句

MyBatis真正强大的功能,在于映射SELECT查询结果到JavaBeans 方面的极大灵活性。

让我们看看一个简单的select查询是怎样(在MyBatis中)配置的,例如以下所看到的:

<select id="findStudentById" parameterType="int" 
resultType="Student">
    SELECT STUD_ID, NAME, EMAIL, PHONE 
        FROM STUDENTS 
    WHERE STUD_ID=#{studId}
</select>

我们能够例如以下调用此语句:

int studId =1;
Student student = sqlSession.selectOne("com.mybatis3.mappers.
StudentMapper.findStudentById", studId);

假设不使用名空间(namespace)和语句id来调用映射语句,你能够通过创建一个映射器Mapper接口。并以类型安全的方式调用方法,例如以下所看到的:

package com.mybatis3.mappers;
public interface StudentMapper
{
    Student findStudentById(Integer studId);
}

你能够使用映射器Mapper接口来调用 updateStudent语句,例如以下所看到的:

StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.findStudentById(studId);

    假设你检查Student对象的属性值,你会发现studId属性值并没有被stud_id列值填充。这是由于MyBatis自己主动对JavaBean中和列名匹配的属性进行填充。这就是为什么name ,email,和phone属性被填充。而studId属性没有被填充。

    为了解决这一问题。我们能够为列名起一个能够与JavaBean中属性名匹配的别名,例如以下所看到的:

<select id="findStudentById" parameterType="int" 
resultType="Student">
    SELECT STUD_ID AS studId, NAME,EMAIL, PHONE 
        FROM STUDENTS 
    WHERE STUD_ID=#{studId}
</select>

如今,Student 这个Bean对象中的值将会恰当地被stud_id,name,email,phone列填充了。

如今,让我们看一下怎样运行返回多条结果的SELECT语句查询。例如以下所看到的:

<select id="findAllStudents" resultType="Student">
    SELECT STUD_ID AS studId, NAME,EMAIL, PHONE 
    FROM STUDENTS
</select>

List<Student> students = 
sqlSession.selectList("com.mybatis3.mappers.StudentMapper.findAllStudents");

映射器Mapper接口StudentMapper能够例如以下定义:

package com.mybatis3.mappers;
public interface StudentMapper
{
    List<Student> findAllStudents();
}

使用上述代码,我们能够例如以下调用 findAllStudents语句

StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.findAllStudents();

假设你注意到上述的SELECT映射定义。你能够看到,我们为全部的映射语句中的stud_id起了别名。

我们能够使用ResultMaps,来避免上述的到处反复别名。我们稍后会继续讨论。

除了java.util.List,你也能够是由其它类型的集合类,如Set,Map,以及(SortedSet)。MyBatis依据集合的类型,会採用适当的集合实现。例如以下所看到的:

  • l 对于List,Collection,Iterable类型,MyBatis将返回java.util.ArrayList
  • l 对于Map类型,MyBatis将返回java.util.HashMap
  • l 对于Set类型,MyBatis将返回 java.util.HashSet
  • l 对于SortedSet类型。MyBatis将返回java.util.TreeSet

3.3 结果集映射ResultMaps

ResultMaps被用来 将SQL SELECT语句的结果集映射到 JavaBeans的属性中。我们能够定义结果集映射ResultMaps而且在一些SELECT语句上引用resultMap。MyBatis的结果集映射ResultMaps特性很强大,你能够使用它将简单的SELECT语句映射到复杂的一对一和一对多关系的SELECT语句上。

3.3.1 简单ResultMap

一个映射了查询结果和Student JavaBean的简单的resultMap定义例如以下:

<resultMap id="StudentResult" type="com.mybatis3.domain.Student">
  <id property="studId" column="stud_id" />
  <result property="name" column="name" />
  <result property="email" column="email" />
  <result property="phone" column="phone" />
</resultMap>

<select id="findAllStudents" resultMap="StudentResult">
    SELECT * FROM STUDENTS
</select>

<select id="findStudentById" parameterType="int" resultMap="StudentResult">
    SELECT * FROM STUDENTS WHERE STUD_ID=#{studId}
</select>

表示resultMap的StudentResult id值应该在此名空间内是唯一的。

而且type属性应该是全然限定类名或者是返回类型的别名。

<result>子元素被用来将一个resultset列映射到JavaBean的一个属性中。

<id>元素和<result>元素功能同样,只是它被用来映射到唯一标识属性,用来区分和比較对象(一般和主键列相相应)。

在<select>语句中。我们使用了resultMap属性。而不是resultType来引用StudentResult映射。当<select>语句中配置了resutlMap属性,MyBatis会使用此数据库列名与对象属性映射关系来填充JavaBean中的属性。


 让我们来看另外一个<select>映射语句定义的样例,如何将查询结果填充到HashMap中。例如以下所看到的:

<select id="findStudentById" parameterType="int" resultType="map">
    SELECT * FROM STUDENTS WHERE STUD_ID=#{studId}
</select>

在上述的<select>语句中,我们将resultType配置成map,即java.util.HashMap的别名。在这样的情况下,结果集的列名将会作为Map中的key值,而列值将作为Map的value值。

HashMap<String,Object> studentMap = sqlSession.selectOne("com.
mybatis3.mappers.StudentMapper.findStudentById", studId);
System.out.println("stud_id :"+studentMap.get("stud_id"));
System.out.println("name :"+studentMap.get("name"));
System.out.println("email :"+studentMap.get("email"));
System.out.println("phone :"+studentMap.get("phone"));

让我们再看一个 使用resultType=”map”,返回多行结果的样例:

<select id="findAllStudents" resultType="map">
    SELECT STUD_ID, NAME, EMAIL, PHONE FROM STUDENTS
</select>

因为resultType=”map”和语句返回多行,则终于返回的数据类型应该是List<HashMap<String,Object>>,例如以下所看到的:

List<HashMap<String, Object>> studentMapList =
    sqlSession.selectList("com.mybatis3.mappers.StudentMapper.findAllS
                          tudents");
for(HashMap<String, Object> studentMap : studentMapList)
{
    System.out.println("studId :" + studentMap.get("stud_id"));
    System.out.println("name :" + studentMap.get("name"));
    System.out.println("email :" + studentMap.get("email"));
    System.out.println("phone :" + studentMap.get("phone"));
}

3.2.2 拓展ResultMap

我们能够从从另外一个<resultMap>,拓展出一个新的<resultMap>,这样,原先的属性映射能够继承过来,以实现。

<resultMap type="Student" id="StudentResult">
  <id property="studId" column="stud_id" />
  <result property="name" column="name" />
  <result property="email" column="email" />
  <result property="phone" column="phone" />
</resultMap>
<resultMap type="Student" id="StudentWithAddressResult" extends="StudentResult">
  <result property="address.addrId" column="addr_id" />
  <result property="address.street" column="street" />
  <result property="address.city" column="city" />
  <result property="address.state" column="state" />
  <result property="address.zip" column="zip" />
  <result property="address.country" column="country" />
</resultMap>

id为StudentWithAddressResult的resultMap拓展了id为StudentResult的resultMap。

假设你仅仅想映射Student数据。你能够使用id为StudentResult的resultMap,例如以下所看到的:

<select id="findStudentById" parameterType="int" 
resultMap="StudentResult">
    SELECT * FROM STUDENTS WHERE STUD_ID=#{studId}
</select>

假设你想将映射Student数据和Address数据。你能够使用id为StudentWithAddressResult的resultMap:

<select id="selectStudentWithAddress" parameterType="int" 
resultMap="StudentWithAddressResult">
SELECT STUD_ID, NAME, EMAIL, PHONE, A.ADDR_ID, STREET, CITY,  
        STATE, ZIP, COUNTRY
    FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON 
            S.ADDR_ID=A.ADDR_ID
    WHERE STUD_ID=#{studId}
</select>

3.4 一对一映射

在我们的域模型例子中,每个学生都有一个与之关联的地址信息。表STUDENTS有一个ADDR_ID列,是ADDRESSES表的外键。

STUDENTS表的例子数据例如以下所看到的:

STUD_ID

NAME

EMAIL

PHONE

ADDR_ID

1

John

john@gmail.com

123-456-7890

1

2

Paul

paul@gmail.com

111-222-3333

2

 

ADDRESSES表的例子输入例如以下所看到的:

ADDR_ID

STREET

CITY

STATE

ZIP

COUNTRY

1

Naperville

CHICAGO

IL

60515

USA

2

Paul

CHICAGO

IL

60515

USA

 

以下让我们看一下如何取Student明细和其Address明细。

 

Student和Address 的JavaBean以及映射器Mapper XML文件定义例如以下所看到的:

public class Address
{
    private Integer addrId;
    private String street;
    private String city;
    private String state;
    private String zip;
    private String country;
    // setters & getters
}
public class Student
{
    private Integer studId;
    private String name;
    private String email;
    private PhoneNumber phone;
    private Address address;
    //setters & getters
}

<resultMap type="Student" id="StudentWithAddressResult">
  <id property="studId" column="stud_id" />
  <result property="name" column="name" />
  <result property="email" column="email" />
  <result property="phone" column="phone" />
  <result property="address.addrId" column="addr_id" />
  <result property="address.street" column="street" />
  <result property="address.city" column="city" />
  <result property="address.state" column="state" />
  <result property="address.zip" column="zip" />
  <result property="address.country" column="country" />
</resultMap>

<select id="selectStudentWithAddress" parameterType="int" 
resultMap="StudentWithAddressResult">
    SELECT STUD_ID, NAME, EMAIL, A.ADDR_ID, STREET, CITY, STATE, 
        ZIP, COUNTRY
    FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON 
        S.ADDR_ID=A.ADDR_ID
    WHERE STUD_ID=#{studId}
</select>

    我们能够使用圆点记法为内嵌的对象的属性赋值。在上述的resultMap中,Student的address属性使用了圆点记法被赋上了address相应列的值。

相同地,我们能够訪问随意深度的内嵌对象的属性。我们能够例如以下訪问内嵌对象属性:

//接口定义
public interface StudentMapper
{
    Student selectStudentWithAddress(int studId);
}


//使用
int studId = 1;
StudentMapper studentMapper =
    sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.selectStudentWithAddress(studId);
System.out.println("Student :" + student);
System.out.println("Address :" + student.getAddress());

    上述例子展示了一对一关联映射的一种方法。然而,使用这样的方式映射,假设address结果须要在其它的SELECT映射语句中映射成Address对象。我们须要为每个语句反复这样的映射关系。MyBatis提供了更好地实现一对一关联映射的方法:嵌套结果ResultMap和嵌套select查询语句。接下来。我们将讨论这两种方式。

3.4.1 使用嵌套结果ResultMap实现一对一关系映射

我们能够使用一个嵌套结果ResultMap方式来获取Student及其Address信息,代码例如以下:

<resultMap type="Address" id="AddressResult">
  <id property="addrId" column="addr_id" />
  <result property="street" column="street" />
  <result property="city" column="city" />
  <result property="state" column="state" />
  <result property="zip" column="zip" />
  <result property="country" column="country" />
</resultMap>
<resultMap type="Student" id="StudentWithAddressResult">
  <id property="studId" column="stud_id" />
  <result property="name" column="name" />
  <result property="email" column="email" />
  <association property="address" resultMap="AddressResult" />
</resultMap>

<select id="findStudentWithAddress" parameterType="int" 
resultMap="StudentWithAddressResult">
    SELECT STUD_ID, NAME, EMAIL, A.ADDR_ID, STREET, CITY, STATE, 
    ZIP, COUNTRY
    FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON 
    S.ADDR_ID=A.ADDR_ID
    WHERE STUD_ID=#{studId}
</select>

元素<association>被用来导入“有一个”(has-one)类型的关联。在上述的样例中,我们使用了<association>元素引用了另外的在同一个XML文件里定义的<resultMap>。

我们也能够使用<association定义内联的resultMap,代码例如以下所看到的:

<resultMap type="Student" id="StudentWithAddressResult">
  <id property="studId" column="stud_id" />
  <result property="name" column="name" />
  <result property="email" column="email" />
  <association property="address" javaType="Address">
    <id property="addrId" column="addr_id" />
    <result property="street" column="street" />
    <result property="city" column="city" />
    <result property="state" column="state" />
    <result property="zip" column="zip" />
    <result property="country" column="country" />
  </association>
</resultMap>

使用嵌套结果ResultMap方式,关联的数据能够通过简单的查询语句(假设须要的话,须要与joins 连接操作配合)进行载入。

 

3.4.2 使用嵌套查询实现一对一关系映射

我们能够通过使用嵌套select查询来获取Student及其Address信息,代码例如以下:

<resultMap type="Address" id="AddressResult">
  <id property="addrId" column="addr_id" />
  <result property="street" column="street" />
  <result property="city" column="city" />
  <result property="state" column="state" />
  <result property="zip" column="zip" />
  <result property="country" column="country" />
</resultMap>

<select id="findAddressById" parameterType="int" 
resultMap="AddressResult">
    SELECT * FROM ADDRESSES WHERE ADDR_ID=#{id}
</select>

<resultMap type="Student" id="StudentWithAddressResult">
  <id property="studId" column="stud_id" />
  <result property="name" column="name" />
  <result property="email" column="email" />
  <association property="address" column="addr_id" select="findAddressById" />
</resultMap>

<select id="findStudentWithAddress" parameterType="int" 
resultMap="StudentWithAddressResult">
    SELECT * FROM STUDENTS WHERE STUD_ID=#{Id}
</select>

在此方式中。<association>元素的 select属性被设置成了id为 findAddressById的语句。这里。两个分开的SQL语句将会在数据库中运行。第一个调用findStudentById载入student信息,而第二个调用findAddressById来载入address信息。

Addr_id列的值将会被作为输入參数传递给selectAddressById语句。

 我们能够例如以下调用findStudentWithAddress映射语句:

StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectStudentWithAddress(studId);
System.out.println(student);
System.out.println(student.getAddress());

3.5 一对多映射

在我们的域模型例子中。一个讲师能够教授一个或者多个课程。这意味着讲师和课程之间存在一对多的映射关系。

我们能够使用<collection>元素将 一对多类型的结果 映射到 一个对象集合上。

TUTORS表的例子数据例如以下:

TUTOR_ID

NAME

EMAIL

PHONE

ADDR_ID

1

John

john@gmail.com

123-456-7890

1

2

Ying

ying@gmail.com

111-222-3333

2

COURSE表的例子数据例如以下:

COURSE_ID

NAME

DESCRIPTION

START_DATE

END_DATE

TUTOR_ID

1

JavaSE

Java SE

2013-01-10

2013-02-10

1

2

JavaEE

Java EE 6

2013-01-10

2013-03-10

2

3

MyBatis

MyBatis

2013-01-10

2013-02-20

2

 

在上述的表数据中,John讲师教授一个课程,而Ying讲师教授两个课程。

 

Course和Tutor的JavaBean定义例如以下:

public class Course
{
    private Integer courseId;
    private String name;
    private String description;
    private Date startDate;
    private Date endDate;
    private Integer tutorId;
    //setters & getters
}
public class Tutor
{
    private Integer tutorId;
    private String name;
    private String email;
    private Address address;
    private List<Course> courses;
    / setters & getters
}

如今让我们看看怎样获取讲师信息以及其所教授的课程列表信息。

<collection>元素被用来将多行课程结果映射成一个课程Course对象的一个集合。和一对一映射一样。我们能够使用嵌套结果ResultMap嵌套Select语句两种方式映射实现一对多映射。

3.5.1 使用内嵌结果ResultMap实现一对多映射

我们能够使用嵌套结果resultMap方式获得讲师及其课程信息,代码例如以下:

<resultMap type="Course" id="CourseResult">
  <id column="course_id" property="courseId" />
  <result column="name" property="name" />
  <result column="description" property="description" />
  <result column="start_date" property="startDate" />
  <result column="end_date" property="endDate" />
</resultMap>
<resultMap type="Tutor" id="TutorResult">
  <id column="tutor_id" property="tutorId" />
  <result column="tutor_name" property="name" />
  <result column="email" property="email" />
  <collection property="courses" resultMap="CourseResult" />
</resultMap>

<select id="findTutorById" parameterType="int" 
resultMap="TutorResult">
SELECT T.TUTOR_ID, T.NAME AS TUTOR_NAME, EMAIL, C.COURSE_ID, 
C.NAME, DESCRIPTION, START_DATE, END_DATE
FROM TUTORS T LEFT OUTER JOIN ADDRESSES A ON T.ADDR_ID=A.ADDR_ID
LEFT OUTER JOIN COURSES C ON T.TUTOR_ID=C.TUTOR_ID
WHERE T.TUTOR_ID=#{tutorId}
</select>

这里我们使用了一个简单的使用了JOINS连接的Select语句获取讲师及其所教课程信息。<collection>元素的resultMap属性设置成了CourseResult,CourseResult包括了Course对象属性与表列名之间的映射。

3.5.2 使用嵌套Select语句实现一对多映射

我们能够使用嵌套Select语句方式获得讲师及其课程信息,代码例如以下:

<resultMap type="Course" id="CourseResult">
  <id column="course_id" property="courseId" />
  <result column="name" property="name" />
  <result column="description" property="description" />
  <result column="start_date" property="startDate" />
  <result column="end_date" property="endDate" />
</resultMap>

<resultMap type="Tutor" id="TutorResult">
  <id column="tutor_id" property="tutorId" />
  <result column="tutor_name" property="name" />
  <result column="email" property="email" />
  <association property="address" resultMap="AddressResult" />
  <collection property="courses" column="tutor_id" select="findCoursesByTutor" />
</resultMap>

<select id="findTutorById" parameterType="int" resultMap="TutorResult">
    SELECT T.TUTOR_ID, T.NAME AS TUTOR_NAME, EMAIL 
    FROM TUTORS T WHERE T.TUTOR_ID=#{tutorId}
</select>
<select id="findCoursesByTutor" parameterType="int" resultMap="CourseResult">
    SELECT * FROM COURSES WHERE TUTOR_ID=#{tutorId}
</select>

    在这样的方式中,<aossication>元素的select属性被设置为id 为findCourseByTutor的语句,用来触发单独的SQL查询载入课程信息。tutor_id这一列值将会作为输入參数传递给findCouresByTutor语句。

public interface TutorMapper
{
    Tutor findTutorById(int tutorId);
}
TutorMapper mapper = sqlSession.getMapper(TutorMapper.class);
Tutor tutor = mapper.findTutorById(tutorId);
System.out.println(tutor);
List<Course> courses = tutor.getCourses();
for (Course course : courses)
{
    System.out.println(course);
}


3.6 动态SQL

有时候,静态的SQL语句并不能满足应用程序的需求。

我们能够依据一些条件,来动态地构建SQL语句。

比如。在Web应用程序中,有可能有一些搜索界面,须要输入一个或多个选项,然后依据这些已选择的条件去运行检索操作。在实现这样的类型的搜索功能。我们可能须要依据这些条件来构建动态的SQL语句。假设用户提供了不论什么输入条件。我们须要将那个条件 加入到SQL语句的WHERE子句中。

MyBatis通过使用<if>,<choose>,<where>,<foreach>,<trim>元素提供了对构造动态SQL语句的高级别支持。

3.6.1 If 条件

<if>元素被用来有条件地嵌入SQL片段。假设測试条件被赋值为true,则对应地SQL片段将会被加入到SQL语句中。

假定我们有一个课程搜索界面,设置了 讲师(Tutor)下拉列表框,课程名称(CourseName)文本输入框。開始时间(StartDate)输入框,结束时间(EndDate)输入框,作为搜索条件。假定课讲师下拉列表是必须选的。其它的都是可选的。

当用户点击 搜索button时,我们须要显示符合下面条件的成列表:

  • l   特定讲师的课程
  • l   课程名 包括输入的课程名称keyword的课程。假设课程名称输入为空。则取全部课程
  • l   在開始时间和结束时间段内的课程

我们能够相应的映射语句。例如以下所看到的:

<resultMap type="Course" id="CourseResult">
  <id column="course_id" property="courseId" />
  <result column="name" property="name" />
  <result column="description" property="description" />
  <result column="start_date" property="startDate" />
  <result column="end_date" property="endDate" />
</resultMap>

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"></select>
    SELECT * FROM COURSES
        WHERE TUTOR_ID= #{tutorId}
    <if test="courseName != null">
    AND NAME LIKE #{courseName}
    </if>
    <if test="startDate != null">
    AND START_DATE >= #{startDate}
    </if>
    <if test="endDate != null">
    AND END_DATE <= #{endDate}
    </if>
</select>

public interface CourseMapper
{
    List<Course> searchCourses(Map<String, Object> map);
}
public void searchCourses()
{
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("tutorId", 1);
    map.put("courseName", "%java%");
    map.put("startDate", new Date());
    CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
    List<Course> courses = mapper.searchCourses(map);
    for (Course course : courses)
    {
        System.out.println(course);
    }
}

此处将生成查询语句 SELECT * FROM COURSES WHERE TUTOR_ID= ?

AND NAME like?

AND START_DATE >= ?。

准备依据给定条件的动态SQL查询将会派上用场。

3.6.2 choose,when 和otherwise 条件

有时候,查询功能是以查询类别为基础的。

首先,用户须要选择是否希望通过选择讲师。课程名称,開始时间,或结束时间作为查询条件类别来进行查询,然后依据选择的查询类别,输入对应的參数。在这种情景中,我们须要仅仅使用当中一种查询类别。

MyBatis 提供了<choose>元素支持此类型的SQL预处理。

如今让我们书写一个适用此情景的SQL映射语句。假设没有选择查询类别。则查询開始时间在今天之后的课程,代码例如以下:

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">
    SELECT * FROM COURSES
    <choose>
        <when test="searchBy == 'Tutor'">
            WHERE TUTOR_ID= #{tutorId}
        </when>
        <when test="searchBy == 'CourseName'">
            WHERE name like #{courseName}
        </when>
        <otherwise>
            WHERE TUTOR start_date >= now()
        </otherwise>
    </choose>
</select>

MyBatis计算<choose>測试条件的值,且使用第一个值为TRUE的子句。假设没有条件为true,则使用<otherwise>内的子句。

3.6.3 where条件

有时候,全部的查询条件(criteria)应该是可选的。在须要使用至少一种查询条件的情况下,我们应该使用WHERE子句。而且, 假设有多个条件,我们须要在条件中加入AND或OR。MyBatis提供了<where>元素支持这样的类型的动态SQL语句。

在我们查询课程界面,我们如果全部的查询条件是可选的。进而。当须要提供一个或多个查询条件时,应该改使用WHERE子句。

<select id="searchCourses" parameterType="hashmap" 
resultMap="CourseResult">
    SELECT * FROM COURSES
    <where> 
        <if test=" tutorId != null ">
            TUTOR_ID= #{tutorId}
        </if>
        <if test="courseName != null">
            AND name like #{courseName}
        </if>
        <if test="startDate != null">
            AND start_date >= #{startDate}
        </if>
        <if test="endDate != null">
            AND end_date <= #{endDate}
        </if>
    </where>
</select>

<where>元素仅仅有在其内部标签有返回内容时才会在动态语句上插入WHERE条件语句。而且,假设WHERE子句以AND或者OR打头,则打头的AND或OR将会被移除。

假设tutor_id參数值为null。而且courseName參数值不为null。则<where>标签会将AND name like#{courseName} 中的AND移除掉,生成的SQL WHERE子句为:where name like#{courseName}。

3.6.4 <trim>条件

<trim>元素和<where>元素类似。可是<trim>提供了在加入前缀/后缀 或者移除前缀/后缀方面提供更大的灵活性。

<select id="searchCourses" parameterType="hashmap" 
resultMap="CourseResult">
SELECT * FROM COURSES
<trim prefix="WHERE" prefixOverrides="AND | OR">
<if test=" tutorId != null ">
TUTOR_ID= #{tutorId}
</if>
<if test="courseName != null">
AND name like #{courseName}
</if>
</trim>
</select>

这里假设随意一个<if>条件为true,<trim>元素会插入WHERE,而且移除紧跟WHERE后面的AND或OR。

3.6.5 foreach循环

另外一个强大的动态SQL语句构造标签即是<foreach>。它能够迭代遍历一个数组或者列表,构造AND/OR条件或一个IN子句。

如果我们想找到tutor_id为1,3,6的讲师所教授的课程,我们能够传递一个tutor_id组成的列表给映射语句,然后通过<foreach>遍历此列表构造动态SQL。

<select id="searchCoursesByTutors" parameterType="map" 
resultMap="CourseResult">
SELECT * FROM COURSES
<if test="tutorIds != null">
<where>
<foreach item="tutorId" collection="tutorIds">
OR tutor_id=#{tutorId}
</foreach>
</where> 
</if> 
</select>

public interface CourseMapper
{
    List<Course> searchCoursesByTutors(Map<String, Object> map);
}
public void searchCoursesByTutors()
{
    Map<String, Object> map = new HashMap<String, Object>();
    List<Integer> tutorIds = new ArrayList<Integer>();
    tutorIds.add(1);
    tutorIds.add(3);
    tutorIds.add(6);
    map.put("tutorIds", tutorIds);
    CourseMapper mapper =
        sqlSession.getMapper(CourseMapper.class);
    List<Course> courses = mapper.searchCoursesByTutors(map);
    for (Course course : courses)
    {
        System.out.println(course);
    }
}

如今让我们来看一下如何使用<foreach>生成 IN子句:

<select id="searchCoursesByTutors" parameterType="map" 
resultMap="CourseResult">
    SELECT * FROM COURSES
    <if test="tutorIds != null">
        <where>
        tutor_id IN
            <foreach item="tutorId" collection="tutorIds" 
            open="(" separator="," close=")">
            #{tutorId}
            </foreach>
        </where>
    </if>
</select>

3.6.6 set条件

<set>元素和<where>元素类似,假设其内部条件推断有不论什么内容返回时。他会插入SET SQL片段。

<update id="updateStudent" parameterType="Student">
    update students 
    <set>
    <if test="name != null">name=#{name},</if>
    <if test="email != null">email=#{email},</if>
    <if test="phone != null">phone=#{phone},</if>
    </set>
    where stud_id=#{id}
</update>

这里,假设<if>条件返回了不论什么文本内容。<set>将会插入setkeyword和其文本内容,而且会剔除将末尾的 “,”。

 在上述的样例中。假设 phone!=null,<set>将会让会移除  phone=#{phone}后的逗号“,”,

生成 set phone=#{phone}


3.7 MyBaits 食谱

除了简化数据库编程外,MyBatis还提供了各种功能。这些对实现一些经常使用任务很实用,比方按页载入表数据,存取CLOB/BLOB类型的数据。处理枚举类型值,等等。让我们来看看当中一些特性吧。

3.7.1  处理枚举类型

MyBatis支持开箱方式持久化enum 类型属性。

如果STUDENTS表中有一列gender(性别)类型为varchar,存储”MALE”或者“FEMALE”两种值。而且,Student对象有一个enum 类型的gender属性,例如以下所看到的:

public enum Gender
{
    FEMALE,
    MALE
}

    默认情况下。MyBatis使用EnumTypeHandler来处理enum类型的Java属性,而且将其存储为enum值的名称。

你不须要为此做不论什么额外的配置。你能够能够向使用基本数据类型属性一样使用enum类型属性,代码例如以下:

public class Student
{
    private Integer id;
    private String name;
    private String email;
    private PhoneNumber phone;
    private Address address;
    private Gender gender;
    //setters and getters
}

<insert id="insertStudent" parameterType="Student" 
useGeneratedKeys="true" keyProperty="id">
insert into students(name,email,addr_id, phone,gender)
values(#{name},#{email},#{address.addrId},#{phone},#{gender})
</insert>

当你运行insertStudent语句的时候,MyBatis会取Gender枚举(FEMALE/MALE)的名称,然后将其存储到GENDER列中。

假设你希望存储原enum的顺序位置。而不是enum名,。你须要明白地配置它。

假设你想存储FEMALE为0,MALE为1到gender列中。你须要在mybatis-config.xml文件里配置EnumOrdinalTypeHandler:

<typeHandler 
handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="com.mybatis3.domain.Gender"/>

3.7.2 处理CLOB/BLOB类型数据

MyBatis提供了内建的对CLOB/BLOB类型列的映射处理支持。

如果我们有例如以下的表结构来存储学生和讲师的照片和简单介绍信息:

CREATE TABLE USER_PICS 
(
ID INT(11) NOT NULL AUTO_INCREMENT,
NAME VARCHAR(50) DEFAULT NULL,
PIC BLOB,
BIO LONGTEXT,
PRIMARY KEY (ID)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=LATIN1;

    这里。照片能够是PNG,JPG或其它格式的。

简单介绍信息能够是学生或者讲师的漫长的人生经历。默认情况下,MyBatis将CLOB类型的列映射到java.lang.String类型上、而把BLOB列映射到byte[] 类型上。

public class UserPic
{
    private int id;
    private String name;
    private byte[] pic;
    private String bio;
    //setters & getters
}

创建UserPicMapper.xml文件,配置映射语句,代码例如以下:

<insert id="insertUserPic" parameterType="UserPic">
    INSERT INTO USER_PICS(NAME, PIC,BIO)
    VALUES(#{name},#{pic},#{bio})
</insert>
<select id="getUserPic" parameterType="int" resultType="UserPic">
    SELECT * FROM USER_PICS WHERE ID=#{id}
</select>

下列的insertUserPic()展示了怎样将数据插入到CLOB/BLOB类型的列上:

public void insertUserPic()
{
    byte[] pic = null;
    try
    {
        File file = new File("C:\\Images\\UserImg.jpg");
        InputStream is = new FileInputStream(file);
        pic = new byte[is.available()];
        is.read(pic);
        is.close();
    }
    catch (FileNotFoundException e)
    {
        e.printStackTrace();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    String name = "UserName";
    String bio = "put some lenghty bio here";
    UserPic userPic = new UserPic(0, name, pic , bio);
    SqlSession sqlSession = MyBatisUtil.openSession();
    try
    {
        UserPicMapper mapper =
            sqlSession.getMapper(UserPicMapper.class);
        mapper.insertUserPic(userPic);
        sqlSession.commit();
    }
    finally
    {
        sqlSession.close();
    }
}

以下的getUserPic()方法展示了如何将CLOB类型数据读取到String类型。BLOB类型数据读取成byte[]属性:

public void getUserPic()
{
    UserPic userPic = null;
    SqlSession sqlSession = MyBatisUtil.openSession();
    try
    {
        UserPicMapper mapper =
            sqlSession.getMapper(UserPicMapper.class);
        userPic = mapper.getUserPic(1);
    }
    finally
    {
        sqlSession.close();
    }
    byte[] pic = userPic.getPic();
    try
    {
        OutputStream os = new FileOutputStream(new
                                               File("C:\\Images\\UserImage_FromDB.jpg"));
        os.write(pic);
        os.close();
    }
    catch (FileNotFoundException e)
    {
        e.printStackTrace();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}

3.7.3 传入多个输入參数

MyBatis中的映射语句有一个parameterType属性来制定输入參数的类型。假设我们想给映射语句传入多个參数的话。我们能够将全部的输入參数放到HashMap中。将HashMap传递给映射语句。

MyBatis 还提供了第二种传递多个输入參数给映射语句的方法。如果我们想通过给定的name和email信息查找学生信息,定义查询接口例如以下:

Public interface StudentMapper
{
    List<Student> findAllStudentsByNameEmail(String name, String email);
}

MyBatis 支持将多个输入參数传递给映射语句,并以#{param}的语法形式引用它们:

<select id="findAllStudentsByNameEmail" resultMap="StudentResult">
    select stud_id, name,email, phone from Students
        where name=#{param1} and email=#{param2}
</select>

这里#{param1}引用第一个參数name,而#{param2}引用了第二个參数email。

StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
studentMapper.findAllStudentsByNameEmail(name, email);

3.7.4 多行结果集映射成Map

假设你有一个映射语句返回多行记录,而且你想以HashMap的形式存储记录的值。使用记录列名作为key值。而记录相应值或为value值。

我们能够使用sqlSession.selectMap(),例如以下所看到的:

<select id=" findAllStudents" resultMap="StudentResult">
    select * from Students
</select>

Map<Integer, Student> studentMap = 
sqlSession.selectMap("com.mybatis3.mappers.StudentMapper.findAllStudents", "studId");

这里studentMap将会将studId作为key值,而Student对象作为value值。

3.7.5 使用RowBounds对结果集进行分页

有时候。我们会须要跟海量的数据打交道。比方一个有数百万条数据级别的表。因为计算机内存的现实我们不可能一次性载入这么多数据,我们能够获取到数据的一部分。特别是在Web应用程序中,分页机制被用来以一页一页的形式展示海量的数据。

MyBatis能够使用RowBounds逐页载入表数据。RowBounds对象能够使用offset和limit參数来构建。參数offset表示開始位置,而limit表示要取的记录的数目。

如果如果你想每页载入并显示25条学生的记录,你能够使用例如以下的代码:

<select id="findAllStudents" resultMap="StudentResult">
    select * from Students
</select>

然后,你能够载入例如以下载入第一页数据(前25条):

int offset =0 , limit =25;
RowBounds rowBounds = new RowBounds(offset, limit);
List<Student> = studentMapper.getStudents(rowBounds);

若要展示第二页,使用offset=25,limit=25;第三页。则为offset=50。limit=25。

3.7.6 使用ResultSetHandler自己定义结果集ResultSet处理

MyBatis在将查询结果集映射到JavaBean方面提供了非常大的选择性。可是。有时候我们会遇到因为特定的目的。须要我们自己处理SQL查询结果的情况。MyBatis提供了ResultHandler插件形式同意我们以不论什么自己喜欢的方式处理结果集ResultSet。

如果我们想从学生的stud_id被用作key。而name被用作value的HashMap中获取到student信息。

对于sqlSession.select()方法。我们能够传递给它一个ResultHandler的实现。它会被调用来处理ResultSet的每一条记录。

public interface ResultHandler
{
    void handleResult(ResultContext context);
}

如今然我们来看一下怎么使用ResultHandler来处理结果集ResultSet,并返回自己定义化的结果。

public Map<Integer, String> getStudentIdNameMap()
{
    final Map<Integer, String> map = new HashMap<Integer, String>();
    SqlSession sqlSession = MyBatisUtil.openSession();
    try
    {
        sqlSession.select("com.mybatis3.mappers.StudentMapper.findAllStude
                          nts",
                          new ResultHandler()
        {
            @Override
            public void handleResult(ResultContext context)
            {
                Student student = (Student) context.getResultObject();
                map.put(student.getStudId(), student.getName());
            }
        }
                         );
    }
    finally
    {
        sqlSession.close();
    }
    return map;
}

     在上述的代码中。我们提供了匿名内部ResultHandler实现类。在handleResult()方法中。我们使用context.getResultObject()获取当前的result对象,即Student对象。由于我们定义了findAllStudent映射语句的resultMap=”studentResult“。对查询返回的每一行都会调用handleResult()方法。而且我们从Student对象中取出studId和name,将其放到map中。

3.7.7 缓存

将从数据库中载入的数据缓存到内存中,是非常多应用程序为了提高性能而採取的一贯做法。

MyBatis对通过映射的SELECT语句载入的查询结果提供了内建的缓存支持。

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

我们能够在SQL映射器XML配置文件里使用<cache />元素加入全局二级缓存。

当你增加了<cache/>元素,将会出现下面情况:

  •         ž 全部的在映射语句文件定义的<select>语句的查询结果都会被缓存
  •         ž 全部的在映射语句文件定义的<insert>,<update> 和<delete>语句将会刷新缓存
  •         ž 缓存依据近期最少被使用(Least Recently Used。LRU)算法管理
  •         ž 缓存不会被不论什么形式的基于时间表的刷新(没有刷新时间间隔)。即不支持定时刷新机制
  •         ž 缓存将存储1024个 查询方法返回的列表或者对象的引用
  •         ž 缓存会被当作一个读/写缓存。这是指检索出的对象不会被共享,而且能够被调用者安全地改动,不会其它潜在的调用者或者线程的潜在改动干扰。(即,缓存是线程安全的)

你也能够通过复写默认属性来自己定义缓存的行为。例如以下所看到的:

<cache eviction="FIFO" flushInterval="60000" size="512" 
readOnly="true"/>

下面是对上述属性的描写叙述:

  •         ž eviction:此处定义缓存的移除机制。

    默认值是LRU,其可能的值有:LRU(least recently used,近期最少使用),FIFO(first infirst out,先进先出),SOFT(soft reference,软引用),WEAK(weak reference,弱引用)。

  •         ž flushInterval:定义缓存刷新间隔,以毫秒计。默认情况下不设置。所以不使用刷新间隔,缓存cache仅仅有调用语句的时候刷新。
  •         ž size:此表示缓存cache中能容纳的最大元素数。

    默认值是1024,你能够设置成随意的正整数。

  •         ž readOnly:一个仅仅读的缓存cache会对全部的调用者返回被缓存对象的同一个实例(实际返回的是被返回对象的一份引用)。一个读/写缓存cache将会返回被返回对象的一分拷贝(通过序列化)。默认情况下设置为false。

    可能的值有false和true。

一个缓存的配置和缓存实例被绑定到映射器配置文件所在的名空间(namespace)上,所以在同样名空间内的全部语句被绑定到一个cache中。

默认的映射语句的cache配置例如以下:

<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>

你能够为随意特定的映射语句复写默认的cache行为;比如。对一个select语句不使用缓存,能够设置useCache=“false”。

除了内建的缓存支持。MyBatis也提供了与第三方缓存类库如Ehcache,OSCache,Hazelcast的集成支持。你能够在MyBatis官方站点https://code.google.com/p/mybatis/wiki/Caches 上找到关于继承第三方缓存类库的很多其它信息。

3.8 总结

     在本章中,我们学习了如何使用映射器配置文件 书写SQL映射语句。讨论了如何配置简单的语句,一对一以及一对多关系的语句,以及如何使用ResultMap进行结果集映射。我们还了解了构建动态SQL语句,结果分页。以及自己定义结果集(ResultSet)处理。在下一章,我们将会讨论如何使用注解书写映射语句。





《Java Persistence with MyBatis 3(中文版)》导航:

Java Persistence with MyBatis 3(中文版)

Java Persistence with MyBatis 3(中文版) 前言

Java Persistence with MyBatis 3(中文版) 第一章 MyBatis入门

Java Persistence with MyBatis 3(中文版) 第二章 引导MyBatis

Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

Java Persistence with MyBatis 3(中文版) 第四章 使用注解配置SQL映射器

Java Persistence with MyBatis 3(中文版) 第五章 与Spring集成 



-------------------------------------------------------------------------------------------------------------------------------

作者声明:本文出处是http://blog.csdn.net/luanlouis,如需转载,请注明出处!






转载于:https://www.cnblogs.com/mfmdaoyou/p/7232543.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值