jdbc 问题分析
- 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
- Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大, sql 变动需要改变java 代码。
- 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
- 对结果集解析存在硬编码(查询列名), sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便
框架要解决的问题:
mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过xml 或注解的方式将要执行的各种statement 配置起来,并通过java 对象和statement 中sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql并将结果映射为 java 对象并返回。
采用 ORM 思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与 jdbc api打交道,就可以完成对数据库的持久化操作。
官网
一、入门
1、创建Maven工程(jar)导入坐标
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--引入lombok的依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
</dependencies>
2、创建POJO
3、创建 UserDao 接口
UserDao 接口就是我们的持久层接口(也可以写成 UserMapper) .我们就写成UserDao ,具体代码如下:
public interface UserDao {
public List<User> findAll();
}
4、创建 UserDao.xml 映射文件
注意:
- 映射配置文件存储的路径在resources里面,要和对应的Dao接口的路径保持一致 (创建目录使用
/
) - 映射配置文件的文件名必须和Dao接口名保持一致
- 一定要引入约束文件
<?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,一个映射配置文件,就对应一个dao接口
根标签的namespace属性的值就对应dao接口的全限定名
-->
<mapper namespace="com.it.dao.UserDao">
<!--
根标签的每一个子标签就对应dao接口的每一个方法:
查询方法就对应select标签
添加方法就对应insert标签
删除方法就对应delete标签
修改方法就对应update标签
标签的parameterType就对应方法的参数类型
标签的id的值对应方法的名字
标签的resultType的值就对应封装结果的类型,如果封装结果的类型是List就对应其泛型的类型
标签体的内容就是要执行的SQL语句
-->
<select id="findAll" resultType="com.it.pojo.User">
select * from t_user
</select>
</mapper>
5、创建 SqlMapConfig.xml 配置文件(核心配置文件)
注意事项
- 存放路径必须是resources的根路径
- 配置文件的名字,随便写
- 一定要引入约束文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--
根标签是configuration
-->
<configuration>
<!--
配置数据库的环境信息:
environments: 表示里面可以配置多个环境,default表示使用哪个环境
environment: 每一个environment表示一种环境
为什么要配置多个环境: 因为我们有多个环境(开发环境、生产环境(真正项目之后运行的环境)、测试环境)
-->
<environments default="dev">
<!--开发环境-->
<environment id="dev">
<!--
事务管理者,type为JDBC表示使用JDBC的事务管理者(了解)
-->
<transactionManager type="JDBC"></transactionManager>
<!--
dataSource表示数据源,1. POOLED表示使用自带连接池 2. UNPOOLED表示不使用连接池 3. JNDI表示使用JNDI的连接池
-->
<dataSource type="POOLED">
<!--连接池的配置信息-->
<property name="username" value=""/>
<property name="password" value=""/>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis_day01?characterEncoding=utf8"/>
</dataSource>
</environment>
<!--生产环境-->
<environment id="pro">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
<!--测试环境-->
<environment id="test">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!--
指定加载哪些映射配置文件: mappers
mapper标签: 每一个mapper标签负责加载一个映射配置文件;resource指定要加载的映射配置文件的路径
-->
<mappers>
<mapper resource="com/it/dao/UserDao.xml"></mapper>
</mappers>
</configuration>
6、测试
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.Test;
public class TestMybatis {
@Test
public void testFindAll() throws Exception {
//1. 让mybatis框架去加载主配置文件
//1.1 将主配置文件SqlMapConfig.xml转换成字节输入流 (需要关闭)
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//1.2 创建一个SqlSessionFactoryBuilder
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
//1.3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = factoryBuilder.build(is); //使用了构建者模式
//1.4 使用sessionFactory对象创建出sqlSession对象 (需要关闭)
SqlSession sqlSession = sessionFactory.openSession(); //使用了工厂模式
//2. 使用sqlSession对象创建出UserDao接口的代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class); //使用了动态代理
//3. 调用userDao代理对象的findAll()方法进行查询
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
//4. 关闭资源
sqlSession.close();
is.close();
}
}
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置
事实上 MyBatis 提供的所有特性都可以利用基于 XML 的映射语言来实现,
ibatis 相关类和接口
SqlSessionFactory
在连接或数据源中创建SqlSession
SqlSessionFactory 常用方法
SqlSession openSession()
Resources 工具类
通过类加载器简化对资源的访问的类
Resources 常用方法
//以Stream对象的形式返回类路径上的资源
public static InputStream getResourceAsStream(String resource)
SqlSession 接口
用于使用MyBatis的主要Java接口。通过这个接口,您可以执行命令、获取映射器和管理事务。
SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
SqlSession 常用方法
//创建绑定到这个SqlSession的映射器(mapper) 接口的代理对象
<T> T getMapper(Class<T> type)
核心配置文件详解
1、properties
使用properties标签引入外部的properties文件
目的: 也是为了配置文件解耦,专门的信息就放到专门的配置文件中
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_day01?characterEncoding=utf-8
jdbc.user=root
jdbc.password=123
引入到核心配置文件
<configuration>
<properties resource="jdbc.properties">
</properties>
<!--数据源配置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="UNPOOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
....
</configuration>
2、typeAliases
使用typeAliases标签定义类的别名,这里面可以定义多个别名
typeAlias就表示定义一个别名,type属性表示要定义别名的那个类的全限定名,alias表示别名
因为所有要配置别名的类基本上都写在一个包中,所以我们可以使用包扫描配置别名package
通过package标签扫描整个包,就能给该包中的所有类都配置别名,别名就是该类的类名(不区分大小写)
核心配置文件
<typeAliases>
<typeAlias type="com.it.bean.User" alias="user"></typeAlias>
<!--<package name="com.it.bean"/>-->
</typeAliases>
映射配置文件
<select id="findAll" resultType="user">
SELECT * FROM user
</select>
3、Mapper
批量配置(包扫描)
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
二、进阶
2.1 基本操作
2.1.1 增:
映射文件:
<insert id="addUser" parameterType="User">
insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>
<!-- 这个 sql 语句中使用#{}字符, #{}代表占位符,我们可以
理解是原来 jdbc 部分所学的?,它们都是代表占位符, 具体的值是由 User 类的
username 属性来决定的。
parameterType 属性:代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的
全名称。-->
关闭资源之前要提交事务:
//提交事务
sqlSession.commit();
新增用户后, 同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。
SelectKey获取主键
<!--
resultType只有select标签才有
我们需要在标签体的SQL语句中,获取pojo类型的参数的属性: #{属性名}
selectKey标签: 查询主键
keyColumn 表示要查询的列名
keyProperty 表示要赋值的属性名
resultType 表示查询出来的结果的类型
order 表示在前或者在后执行
select last_insert_id() 查询最后一个自增长的id的值,只适用与自增主键
-->
<insert id="addUser" parameterType="User">
<selectKey resultType="int" order="AFTER" keyProperty="uid" keyColumn="uid">
select last_insert_id()
</selectKey>
insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>
Mybatis新增数据,存在就更新,不存在就添加,Mysql避免重复插入数据的4种方式
1)ON DUPLICATE KEY UPDATE
是Mysql特有的语法,仅Mysql有效。
#-- 在原sql后面增加 ON DUPLICATE KEY UPDATE
INSERT INTO test ( id, NAME, age )
VALUES( 1, '张三', 13 )
ON DUPLICATE KEY UPDATE id = 1,
NAME = '张三',
age = 133
ON DUPLICATE KEY UPDATE子句写的是固定值,怎么动态赋值呢?如果一次插入多条数据,怎么动态获取主键冲突所要更新的值呢?
ON DUPLICATE KEY UPDATE age = VALUES(age)
- ON DUPLICATE KEY UPDATE检查主键或唯一索引字段是否冲突。
- update的字段值与现存的字段值相同,则不更新。
- 动态更新字段值用VALUES(字段名称)。
2.1.2 删:
<!--
int deleteById(int id);
我们需要在标签体的SQL语句中,获取简单类型的参数,我们使用#{任意字符串}
-->
<delete id="deleteById" parameterType="int">
delete from t_user where uid=#{id}
</delete>
2.1.3 改:
<!--void updateUser(User user);-->
<update id="updateUser" parameterType="User">
update t_user set username=#{username},sex=#{sex},address=#{address} where uid=#{uid}
</update>
2.1.4 模糊查询
<!--
模糊查询
另外一种在SQL语句中引用方法的参数的方式:${}(直接拼接,而#{}是?占位符)
1. 引用pojo中的属性: '${属性名}'
2. 引用简单类型的参数: '${value}',但是高版本的mybatis中可以'${任意字符串}'
-->
<select id="searchByUsername" parameterType="string" resultType="User">
<!--select * from t_user where username like "%"#{username}"%"-->
<!--select * from t_user where username like concat("%",#{username},"%")-->
select * from t_user where username like '%${value}%'
</select>
注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。
#{}与${}的区别
- #{}一定不能写在引号里面,${}一定要写在引号里面
- 如果是pojo、map类型的参数,无论是#{}还是${}里面都是些属性名
- 如果是简单类型的参数,#{}里面可以写任意字符串,但是${}里面只能写value(以前的版本)
- 如果使用#{}引入参数的话,其实是先使用?占位符,然后再设置参数;而使用${}引入参数的话,是直接拼接SQL语句
日志的使用
我们在使用MyBatis的时候, 其实MyBatis框架会打印一些必要的日志信息, 在开发阶段这些日志信息对我们分析问题,理解代码的执行是特别有帮助的; 包括项目上线之后,我们也可以收集项目的错误日志到文件里面去; 所以我们采用专门的日志系统来处理.
1、导入坐标:
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
<!-- log end -->
2、拷贝log4j.properties到resources目录
log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#[%-5p] %t %l %d %rms:%m%n
#%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %t %l %d %rms:%m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\idea_project\\it_mm_backend.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n
级别:error > warn > info>debug>trace
- 开发阶段: log4j.rootLogger= debug,std,file
- 上线之后: log4j.rootLogger= error ,file
parameterType深入
3.1 传递简单类型
单个参数,方法就以简单类型传入即可,那么在映射配置文件中的parameterType的值就是这个简单类型的别名;在SQL语句中引入简单类型的参数#{任意字符串}
User findById(int id);
<select id="findById" parameterType="int" resultType="User">
select * from t_user where uid=#{id}
</select>
3.2 传递 pojo 对象 或者 Map
- 将多个参数封装到一个POJO中,那么在映射配置文件中parameterType的值就是这个POJO的全限定名或者别名; 在SQL语句中引入参数#{POJO的属性名}或者’${POJO的属性名}’
- 将多个参数封装到一个Map中(要封装的参数没有对应的POJO),那么在映射配置文件中parameterType的值是map; 在SQL语句中引入参数#{map的key}或者’${map的key}’
void addUser(User user);
void updateUser(Map map);
<insert id="addUser" parameterType="User">
insert into t_user(username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>
<update id="updateUser" parameterType="map">
update t_user set username=#{username},sex=#{sex} where uid=#{uid}
</update>
3.3 传递多个参数
使用Param注解指定参数名称
User findByUsernameAndAddress(@Param("uname") String username, @Param("addr") String address);
<select id="findByUsernameAndAddress" resultType="User">
select * from t_user where username=#{uname} and address=#{addr}
</select>
3.4传递 pojo 包装对象类型
pojo 包装对象:pojo 中的属性类型又是其它的pojo
通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。Pojo 类中包含 pojo。
需求:根据用户id查询用户信息并进行分页,查询条件放到 QueryVo 的 user 属性中。
- QueryVo
// * Vo ViewObject 视图对象
// * QueryVo 就是封装查询视图的数据
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryVo {
public QueryVo(Long currentPage, Integer pageSize, User queryCondition) {
this.currentPage = currentPage;
this.pageSize = pageSize;
this.queryCondition = queryCondition;
}
private Long currentPage;
private Integer pageSize;
/**
* 查询条件
*/
private User queryCondition;
private Long offset;
public Long getOffset() {
return (currentPage - 1)*pageSize;
}
}
- UserDao接口
public interface UserDao {
List<User> searchByCondition(QueryVo queryVo);
}
- UserDao.xml文件
<select id="searchByCondition" parameterType="QueryVo" resultType="User">
select * from t_user where sex=#{queryCondition.sex} and address=#{queryCondition.address}
limit #{offset},#{pageSize}
</select>
- 测试代码
@Test
public void test03(){
SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = new User();
user.setSex("男");
user.setAddress("北京");
QueryVo queryVo = new QueryVo(1l,5,user);
List<User> userList = mapper.searchByCondition(queryVo);
for (User user1 : userList) {
System.out.println(user1);
}
SqlSessionFactoryUtil.commitAndClose(sqlSession);
}
2.1 动态 SQL
动态 SQL 是 MyBatis 的强大特性之一。
根据不同条件拼接 SQL 语句
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,
2.1.1 foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>
collection - 指定集合属性的名称,这里是list
open - 指定拼接SQL的开头前缀,这里是“(”
separator - 分隔符,这里是“,”
close - 指定拼接SQL的结束尾缀,这里是“)”
item - 代表当前遍历集合中一个元素,这里是一个name
index - 索引变量
foreach 元素的功能非常强大,允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
2.2 结果映射 (resultMap)
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作
有时,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
<select id="selectUsers" resultType="map">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型。
MyBatis 对JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)都提供了支持
2.2.1 类型别名
类型别名是你的好帮手。使用它们,你就可以不用输入类的全限定名了。
<!-- mybatis-config.xml 中 -->
<typeAlias type="com.someapp.model.User" alias="User"/>
<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultType="User">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。
这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。
2.2.2 列名和属性名不能匹配上
1)如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。比如:
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
2)解决列名不匹配的另外一种方式。
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
2.2.3 高级结果映射
MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序,那就太好了,但可惜也没有。 而 ResultMap 就是 MyBatis 对这个问题的答案。
resultMap
元素有很多子元素和一个值得深入探讨的结构
<!-- 非常复杂的语句 -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
A.id as author_id,
A.username as author_username,
A.password as author_password,
A.email as author_email,
A.bio as author_bio,
A.favourite_section as author_favourite_section,
P.id as post_id,
P.blog_id as post_blog_id,
P.author_id as post_author_id,
P.created_on as post_created_on,
P.section as post_section,
P.subject as post_subject,
P.draft as draft,
P.body as post_body,
C.id as comment_id,
C.post_id as comment_post_id,
C.name as comment_name,
C.comment as comment_text,
T.id as tag_id,
T.name as tag_name
from Blog B
left outer join Author A on B.author_id = A.id
left outer join Post P on B.id = P.blog_id
left outer join Comment C on P.id = C.post_id
left outer join Post_Tag PT on PT.post_id = P.id
left outer join Tag T on PT.tag_id = T.id
where B.id = #{id}
</select>
<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
<result property="favouriteSection" column="author_favourite_section"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>
resultMap 属性
id
当前命名空间中的一个唯一标识,用于标识一个结果映射。
type
类的完全限定名, 或者一个类型别名
autoMapping
如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。
resultMap 子元素
1) constructor
用于在实例化类时,注入结果到构造方法中
- idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
- arg - 将被注入到构造方法的一个普通结果
2) id 、result
这些元素是结果映射的基础。id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。
这两者之间的唯一不同是,id 元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。
关联
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>
关联(association)元素处理“有一个”类型的关系。
需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。
MyBatis 有两种不同的方式加载关联:
嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。
属性:
property
:映射到列结果的字段或属性。JavaBean 中给定名字的属性
javaType
: 一个 Java 类的完全限定名,或一个类型别名
jdbcType
: JDBC 类型,所支持的 JDBC 类型参见这个表格之前的“支持的 JDBC 类型”
typeHandler
: 使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的完全限定名,或者是类型别名
association
– 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
collection
– 一个复杂类型的集合
- 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
discriminator
– 使用结果值来决定使用哪个 resultMap
- case – 基于某些值的结果映射
– 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
column属性:引用结果集
property属性:引用JavaBean 中的属性