MyBatis
一.简介
1.是什么
MyBatis是一个优秀的基于java的持久层框架,它内部封装了JDBC,使开发者只需要关注SQL语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
MyBatis通过XML或注解的方式将要执行的各种statement配置起来,并通过JAVA对象和statement中SQL的动态参数进行映射生成最终执行的SQL语句。
最后MyBatis框架执行SQL并将结果映射为Java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对JDBC进行了封装,屏蔽了JDBC API底层访问细节,使我们不用与JDBC API打交道,就可以完成对数据库的持久化操作
简单说就是:有一种叫MyBatis的持久层技术,能够代替JDBC,简化JDBC开发。
2.ORM
对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用“虚拟对象数据库”。
简单的说:就是把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表。
数据库 | 实体类 |
---|---|
user表 | User类 |
id列 | id属性 |
username列 | userName属性 |
age列 | age属性 |
二.环境及测试
1.建立普通的Maven项目,导入依赖
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- log4j依赖 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
2.建表
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`age` int(11) NULL DEFAULT NULL,
`gender` varchar(6) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`addr` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;
INSERT INTO `user` VALUES (1, 'zhangsan', '123', 20, 'male', 'qd');
INSERT INTO `user` VALUES (2, 'lisi', '123', 21, 'male', 'bj');
INSERT INTO `user` VALUES (4, 'tom', '123', 19, 'male', 'nj');
INSERT INTO `user` VALUES (5, 'wangwu', '123', 20, 'male', 'sh');
INSERT INTO `user` VALUES (6, 'weihua', '111', 21, 'female', 'sz');
3.实体类
/**
* 表示用户的实体类
*
* 属性名和数据库表名对应
*
* 符合JavaBean的规范
*/
public class User {
private Long id;
private String username;
private String password;
private Integer age;
private String gender;
private String addr;
//set和get方法
//toString方法
}
4.其他文件
编写映射文件UserMapper.xml
放在resources目录下的mappers
<?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="userMapper">
<select id="findAll" resultType="tech.code2048.bean.User">
SELECT * FROM user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 映射文件DTD约束,用来约束XML中的标签,直接从素材中拷贝就可以,不需要去记。-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 映射文件的根标签,其他的内容都要写在该标签的内部
namespace:命名空间,与下面语句的id一起组成查询的标识,唯一的确定要执行的SQL语句
-->
<mapper namespace="userMapper">
<!-- select标签表示这是一个查询操作,除了这个标签还可以有insert、delete、update
id:语句的id,和上面的namespace一起组成查询的标识,唯一的确定要执行的SQL语句
resultType:查询结果对应的实体类型,目前这里先写全类名(包名+类名)
-->
<select id="findAll" resultType="tech.code2048.bean.User">
<!-- SQL语句 -->
SELECT * FROM user
</select>
</mapper>
编写核心配置文件SqlMapConfig.xml
<?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">
<!-- 配置环境
default:指定默认环境,如果下面配置了多个id,通过delfault属性的值指定使用哪个环境
-->
<configuration>
<!-- 配置环境 -->
<environments default="dev">
<environment id="dev">
<!-- type:事务管理器类型,类型有如下两种。
JDBC:这个配置就是直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。
默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将closeConnection属性设置
为false来阻止它默认的关闭行为。
-->
<transactionManager type="JDBC"></transactionManager>
<!-- type:指定数据源类型,类型有如下三种。
UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
JNDI:这个数据源的实现是为了能在如EJB或应用服务器这类容器中使用,
容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
-->
<dataSource type="POOLED">
<!-- 配置数据源的基本参数 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 加载映射配置文件,该标签的作用是加载映射文件,加载方式有如下几种:
使用相对于类路径的资源引用 <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
使用完全限定资源定位符(URL),例如:
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
使用映射器接口实现类的完全限定类名,例如:
<mapper class="org.mybatis.builder.AuthorMapper"/>
将包内的映射器接口实现全部注册为映射器,例如:
<package name="org.mybatis.builder"/>-->
<mappers>
<mapper resource="mappers/UserMapper.xml" />
</mappers>
</configuration>
properties标签
将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件
创建配置数据源的配置文件jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useSSL=false
jdbc.username=root
jdbc.password=root
typeAliases标签
写法1
<!-- 配置别名 -->
<typeAliases>
<typeAlias type="tech.code2048.bean.User" alias="user" />
</typeAliases>
通过上面的配置为tech.code2048.bean包下的User类起了一个别名user。这种写法需要为每个类分别设置别名,如果类很多,这里的配置会很繁琐。
写法2
<!-- 配置别名 -->
<typeAliases>
<package name="tech.code2048.bean"/>
</typeAliases>
这种写法为tech.code2048.bean下的所有类设置别名,别名为类名的首字母小写。
编写日志配置文件
log4j.properties 直接复制即可
#
# Hibernate, Relational Persistence for Idiomatic Java
#
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
#
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
级别 | 描述 |
---|---|
ALL LEVEL | 打开所有日志记录开关;是最低等级的,用于打开所有日志记录 |
DEBUG | 输出调试信息;指出细粒度信息事件对调试应用程序是非常有帮助的 |
INFO | 输出提示信息;消息在粗粒度级别上突出强调应用程序的运行过程 |
WARN | 输出警告信息;表明会出现潜在错误的情形 |
ERROR | 输出错误信息;指出虽然发生错误事件,但仍然不影响系统的继续运行 |
FATAL | 输出致命错误;指出每个严重的错误事件将会导致应用程序的退出 |
OFF LEVEL | 关闭所有日志记录开关;是最高等级的,用于关闭所有日志记录 |
5.测试
public class MyTest {
@Test
public void test1() throws IOException {
//加载核心配置文件
InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml");
//获得sqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(stream);
//获得sqlSession对象
SqlSession sqlSession = factory.openSession();
//执行sql语句
List<User> list = sqlSession.selectList("userMapper.findAll");
//打印结果
list.forEach(System.out::println);
//释放资源
sqlSession.close();
}
}
三.使用(代理开发方式)
1.介绍
MyBatis
代理开发方式实现Dao
层的开发。
Mapper
接口开发方法只需要程序员编写Mapper
接口(相当于Dao
接口),由MyBatis
框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao
接口实现类方法。
需要遵循的规范:
Mapper.xml
文件中的namespace
与mapper
接口的全限定名相同;Mapper
接口方法名和Mapper.xml
中定义的每个statement
的id
相同;Mapper
接口方法的输入参数类型和mapper.xml
中定义的每个sql
的parameterType
的类型相同;Mapper
接口方法的返回值类型和mapper.xml
中定义的每个sql
的resultType
的类型相同。
约定大于配置
2.准备
1.实体类
public class User {
private Long id;
private String username;
private String password;
private Integer age;
private String gender;
private String addr;
//set、get
//toString
}
2.下载MyBatisX插件
3.CRUD操作
1.编写UserMapper接口
public interface UserMapper {
void add(User user);
void delete(int id);
void chg(User user);
User findById(int id);
List<User> findAll();
}
2.映射文件
<?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">
<!-- namespace和接口的全限定类名相同 -->
<mapper namespace="tech.code2048.mapper.UserMapper">
<!--
id和接口中对应方法的方法名相同
parameterType的类型和接口中对应方法的参数类型相同
-->
<insert id="add" parameterType="user">
insert into user(username, password, age, gender, addr) values(#{username}, #{password}, #{age}, #{gender}, #{addr})
</insert>
<delete id="delete" parameterType="int">
DELETE FROM user WHERE id=#{id}
</delete>
<update id="chg" parameterType="user">
UPDATE user SET username=#{username}, password=#{password} WHERE id=#{id}
</update>
<!--
resultType的类型和接口中对应方法的返回值类型相同
-->
<select id="findById" parameterType="int" resultType="user">
SELECT * FROM user WHERE id=#{id}
</select>
<select id="findAll" resultType="user">
SELECT * FROM user
</select>
</mapper>
3.核心文件SqlMapConfig.xml
<?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>
<typeAliases>
<package name="tech.code2048.bean"/>
</typeAliases>
<!-- 配置环境 -->
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 加载映射配置文件 -->
<mappers>
<mapper resource="tech/code2048/mapper/UserMapper.xml" />
</mappers>
</configuration>
4.测试类
public class MyTest {
private SqlSession sqlSession;
private UserMapper userMapper;
@Before
public void init() throws IOException {
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取连接
sqlSession = factory.openSession();
//创建接口的代理对象
userMapper = sqlSession.getMapper(UserMapper.class);
}
@After
public void destroy() {
//关闭连接
sqlSession.close();
}
@Test
public void testFindById() {
User user = userMapper.findById(1);
System.out.println(user);
}
@Test
public void testFindAll() {
List<User> users = userMapper.findAll();
users.forEach(user -> System.out.println(user));
}
}
项目结构如下所示
4.参数绑定
需要传两个参数时
4.1序号参数绑定
UserMapper
List<User> findByNameAndGender(Integer age , String gender);
UserMapper.xml
<select id="findByNameAndGender" resultType="com.stedu.bean.User">
SELECT * FROM `user` where age=#{param1} and gender=#{param2}
</select>
java 测试类
@Test
public void testfindbynameandage() {
List<User> byNameAndGender = userMapper.findByNameAndGender(20,"male");
byNameAndGender.forEach(System.out::println);
}
用param1 param2 或 arg0 arg1代替
4.2注解参数绑定
UserMapper
List<User> findByNameAndGender1(@Param("age") Integer age ,@Param("gender") String gender);
UserMapper.xml
<select id="findByNameAndGender1" resultType="com.stedu.bean.User">
SELECT * FROM `user` where age=#{age} and gender=#{gender}
</select>
java 测试类
@Test
public void testfindbynameandage1() {
List<User> byNameAndGender = userMapper.findByNameAndGender1(20,"male");
byNameAndGender.forEach(System.out::println);
}
4.3Map参数绑定
UserMapper
List<User> findByMap(Map<String , Object> map);
UserMapper.xml
<select id="findByMap" resultType="com.stedu.bean.User">
SELECT * FROM `user` where age=#{age} and gender=#{gender}
</select>
java 测试类
@Test
public void testfindbynameandage2() {
HashMap<String, Object> map = new HashMap<>();
map.put("age", 20);
map.put("gender", "male");
List<User> byNameAndGender = userMapper.findByMap(map);
byNameAndGender.forEach(System.out::println);
}
4.4对象参数绑定
UserMapper
User fingByObj(User user);
UserMapper.xml
<select id="fingByObj" resultType="user">
<!-- 占位符的名字和参数实体类属性的名字相同 -->
select * from user where username=#{username} and password=#{password}
</select>
java 测试类
@Test
public void testFindByObj() {
User user = new User();
user.setUsername("admin");
user.setPassword("123456");
User u = userMapper.fingByObj(user);
System.out.println(u);
}
5.模糊查询
UserMapper
List<User> findByName(String username);
UserMapper.xml
<select id="findByName" resultType="com.stedu.bean.User">
SELECT * FROM `user` where `username` like concat('%',#{username},'%')
</select>
java 测试类
@Test
public void testFindByName() {
List<User> users = userMapper.findByName("zhang");
users.forEach(System.out::println);
}
6.主键回填
6.1 last_insert_id()查询主键
适用于整数类型自增主键
<insert id="add" parameterType="user">
<selectKey keyColumn="id" keyProperty="id" resultType="long" order="AFTER">
<!-- 适用于整数类型自增主键 -->
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username, password, age, gender, addr) values(#{username}, #{password}, #{age}, #{gender}, #{addr})
</insert>
6.2通过uuid()查询主键
适用于字符类型主键
<?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="tech.code2048.mapper.ProductMapper">
<insert id="add" parameterType="product">
<selectKey keyProperty="id" keyColumn="id" resultType="string" order="BEFORE">
<!-- 适用于字符类型主键 -->
SELECT REPLACE(UUID(),'-','')
</selectKey>
insert into product(id, name) values(#{id}, #{name})
</insert>
</mapper>
7.动态SQL语句
7.1介绍
有很多时候,业务逻辑变化时,需要SQL语句是动态变化的。如名字为空时查询全部,不为空时模糊查询。
7.2 if
UserMapper
List<User> findByAgeAndAddr(@Param("age")Integer age,@Param("addr") String addr);
UserMapper.xml
<!-- 动态sql -->
<select id="findByAgeAndAddr" resultType="com.stedu.bean.User">
select * from `user`
<where>
<if test="age!=null">
and `age`=#{age}
</if>
<if test="addr!=null">
and `addr`=#{addr}
</if>
</where>
</select>
或把where写在外面
<select id="findByCondition" resultType="user">
<!-- 注意这里的where 1=1 -->
select * from user where 1=1
<if test="age!=null">
and age=#{age}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</select>
7.3 set
我们根据实体类属性的不同取值,使用不同的SQL语句来进行修改。比如在age
不为空时对age
进行修改,如果gender
不为空时还要对gender
进行修改。
Integer Update(User user);
<update id="Update" parameterType="user">
update `user`
<set>
<if test="username!=null and username.length>0">
`username`=#{username}
</if>
<if test="password!=null and password.length>0">
`password`=#{password}
</if>
<if test="age!=null and age.length>0">
`age`=#{age}
</if>
<if test="gender!=null and gender.length>0">
`gender`=#{gender}
</if>
<if test="addr!=null and addr.length>0">
`addr`=#{addr}
</if>
</set>
where `id`=#{id}
</update>
7.4 trim
<trim prefix="" suffix="" prefixOverrides="" suffixOverrides="">`代替`<where>、<set>
<!--
prefix:自动加入前缀
prefixOverrides:自动忽略第一个“and”或者“or”
-->
<select id="findByCondition1" resultType="user">
select * from user
<trim prefix="where" prefixOverrides="and|or">
<if test="age!=null">
and age=#{age}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</trim>
</select>
<!--
prefix:自动加入前缀
suffixOverrides:自动忽略最后一个”,“
-->
<update id="chgByCondition1" parameterType="user">
update t_users
<trim prefix="set" suffixOverrides=",">
<if test="age!=null">
age=#{age},
</if>
<if test="gender!=null">
gender=#{gender},
</if>
</trim>
where id=#{id}
</update>
7.5 foeach
循环
例子:根据id范围查找
List<User> findbyids(List<Object> ids);
<select id="findbyids" resultType="com.stedu.bean.User">
SELECT * from `user`
<where>
<foreach collection="list" item="id" open="id in (" separator="," close=")">
#{id}
</foreach>
</where>
</select>
7.6 SQL片段抽取
目的:将重复的SQL提取出来,使用时用include引用即可,最终达到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="tech.code2048.mapper.UserMapper">
<sql id="selectAll">
SELECT * FROM user
</sql>
<select id="findAll" resultType="user">
<include refid="selectAll" />
</select>
<select id="findByCondition" resultType="user">
<include refid="selectAll" />
<where>
<if test="age!=null">
and age=#{age}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</where>
</select>
<select id="findByIds" resultType="user">
<include refid="selectAll" />
<where>
<foreach collection="list" open="id in (" close=")" separator="," item="id">
#{id}
</foreach>
</where>
</select>
</mapper>
8.多表查询
8.1一对一查询
OrderMapper.xml
<!--
resultMap:完成结果映射,表的字段到对象属性的映射,在表的字段名和对象属性名不相同时通常会被用到
id:设置主键列的对应关系
result:设置普通列的对应关系
column:表的字段名
property:对象的属性名
这种映射关系了解即可,通常不用这种方式
-->
<!--
<resultMap id="orderMap" type="order">
<id column="id" property="id" />
<result column="ordertime" property="ordertime" />
<result column="total" property="total" />
<result column="uid" property="user.id" />
<result column="username" property="user.username" />
<result column="password" property="user.password" />
</resultMap>
-->
<resultMap id="orderMap" type="order">
<id column="id" property="id" />
<result column="ordertime" property="ordertime" />
<result column="total" property="total" />
<!--
association:用于建立一对一的关系
javaType:指定属性的类型
-->
<association property="user" javaType="user">
<id column="uid" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
</association>
</resultMap>
<!--
resultMap:用于指定要使用的resultMap
-->
<select id="findAll" resultMap="orderMap">
SELECT
o.*, u.id uid, u.username username, u.password password
FROM
`order` o, user u
WHERE
o.uid=u.id;
</select>
或者
UserMapper.xml
<?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="tech.code2048.mapper.OrderMapper">
<resultMap id="orderMap" type="order">
<id column="id" property="id" />
<result column="ordertime" property="ordertime" />
<result column="total" property="total" />
<!--
association:用于建立一对一的关系
javaType:指定属性的类型
column: 数据库中的列名,或者是列的别名,被设置为对应嵌套Select语句的参数
select:用于加载复杂类型属性的映射语句的 ID,
它会从 column 属性指定的列中检索数据,作为参数传递给目标 select 语句。
注意这里select中的写法,这里需要UserMapper.xml中相应ID处有对应的SQL语句
-->
<association property="user" column="uid" javaType="user" select="tech.code2048.mapper.UserMapper.findById" />
</resultMap>
<select id="findAll" resultMap="orderMap">
SELECT * FROM `order`
</select>
</mapper>
<?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="tech.code2048.mapper.UserMapper">
<select id="findById" resultType="user">
SELECT * FROM user WHERE id=#{id}
</select>
</mapper>
8.2 一对多查询
<mapper namespace="tech.code2048.mapper.UserMapper">
<resultMap id="userMap" type="user">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
<!--
collection:关联一个集合
-->
<collection property="orders" ofType="order">
<id column="oid" property="id" />
<result column="ordertime" property="ordertime" />
<result column="total" property="total" />
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
SELECT
u.*, o.id oid, o.ordertime ordertime, o.total total
FROM
user u, `order` o
WHERE
u.id=o.uid;
</select>
</mapper>
或者
UserMapper.xml
<?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="tech.code2048.mapper.UserMapper">
<resultMap id="userMap" type="user">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
<!--
collection:关联一个集合
column: 数据库中的列名,或者是列的别名,被设置为对应嵌套Select语句的参数
select:用于加载复杂类型属性的映射语句的 ID,
它会从 column 属性指定的列中检索数据,作为参数传递给目标 select 语句。
注意这里select中的写法,这里需要UserMapper.xml中相应ID处有对应的SQL语句
-->
<collection property="orders" column="id" ofType="order" select="tech.code2048.mapper.OrderMapper.findByUid" />
</resultMap>
<select id="findAll" resultMap="userMap">
SELECT * FROM user
</select>
</mapper>
OrderMapper.xml
<?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="tech.code2048.mapper.OrderMapper">
<select id="findByUid" resultType="order">
SELECT * FROM `order` WHERE uid=#{id}
</select>
</mapper>
8.3 多对多查询
SysUserMapper.xml
<?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="tech.code2048.mapper.SysUserMapper">
<resultMap id="userMap" type="sysuser">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="email" property="email" />
<result column="password" property="password" />
<result column="phoneNum" property="phoneNum" />
<collection property="roles" ofType="sysrole">
<id column="rid" property="id" />
<result column="roleName" property="roleName" />
<result column="roleDesc" property="roleDesc" />
</collection>
</resultMap>
<select id="findAll" resultType="sysuser" resultMap="userMap">
SELECT
u.*, r.id rid, r.roleDesc roleDesc, r.roleName roleName
FROM
sys_user u, sys_user_role ur, sys_role r
WHERE
u.id=ur.userId AND r.id=ur.roleId
</select>
</mapper>
SysRoleMapper.xml
<?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="tech.code2048.mapper.SysRoleMapper">
<resultMap id="roleMap" type="sysrole">
<id column="id" property="id" />
<result column="roleName" property="roleName" />
<result column="roleDesc" property="roleDesc" />
<collection property="users" ofType="sysuser">
<id column="uid" property="id" />
<result column="username" property="username" />
<result column="email" property="email" />
<result column="password" property="password" />
<result column="phoneNum" property="phoneNum" />
</collection>
</resultMap>
<select id="findAll" resultMap="roleMap">
SELECT
r.*, u.id uid, u.username username, u.`password` `password`, u.email email, u.phoneNum phoneNum
FROM
sys_user u, sys_user_role ur, sys_role r
WHERE
u.id=ur.userId AND r.id=ur.roleId
</select>
</mapper>