https://mybatis.org/mybatis-3/zh/getting-started.html
持久层框架
,它支持自定义 SQL、存储过程以及高级映射。普通的java的项目只需要将mybatis-xxx.jar
文件引入项目即可。
Maven
构建的项目,则将jar包依赖引入pom.xml文件即可:
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.3version>
dependency>
思路:搭建环境–> 导入mybatis–>编写代码–>测试!
1.搭建环境
创建数据库表格
CREATE DATABASE `mybatis`;
USE `mybatis`;
CREATE TABLE `user` (
`id` INT ( 11 ) NOT NULL PRIMARY KEY,
`name` VARCHAR ( 255 ) DEFAULT NULL,
`pwd` VARCHAR ( 255 ) DEFAULT NULL,
`age` INT ( 200 ) NOT NULL DEFAULT 0
) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8;
INSERT INTO `user` ( `name`, `pwd`, `age` )
VALUES
( '张三', '123', 18 ),
( '李四', '456', 24 ),
( '王五', '789', 20 ),
( '无极', '258', 30 ),
( '邓泉', '147', 16 );
新建一个maven项目
2.导入依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.46version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.4version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
dependency>
3.编写代码
编写核心配置文件 通过这个方法可以获取sqlsession对象,从而操作mapper接口
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
private static String resource = "mybatis-config.xml";
static {
try {
//使用mybatis第一步:获取sqlsessionFactory工厂对象
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取sqlsession对象
* @return
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
创建user对象
package com.potato.pojo;
import lombok.Data;
/**
* \* Created with IntelliJ IDEA.
* \* User: 一颗小土豆
* \* Date: 2020/5/30
* \* Time: 15:40
*/
@Data //使用lombok注解
public class User {
private Integer id;
private String name;
private String pwd;
private Integer age;
}
创建mapper.java接口和mapper.xml映射文件
mapper.java
public interface UserMapper {
//查询所有的user
List<User> getAll();
}
mapper.xml
<mapper namespace="com.potato.mapper.UserMapper">
<select id="getAll" resultType="com.potato.pojo.User">
select * from `user`
select>
mapper>
在mybatis-config.xml中 配置mapper.xml
<mappers>
<package name="com.potato.mapper">package>
mappers>
在pom.xml中配置resources的文件输出,如果不配置会导致mapper.xml编译不到,导致找不到mapper.xml该文件
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
4.测试
public class UserMapperTest {
@Test
public void test1(){
//获得SqlSession
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获得mapper接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//执行查询方法
List<User> userList = mapper.getAll();
//打印输出
userList.forEach(System.out::println);
/*结果:
* User(id=1, name=张三, pwd=123, age=18)
* User(id=2, name=李四, pwd=456, age=24)
* User(id=3, name=王五, pwd=789, age=20)
* User(id=4, name=无极, pwd=258, age=30)
* User(id=5, name=邓泉, pwd=147, age=16)
*/
}
}
UserMapper.xml
<mapper namespace="com.potato.mapper.UserMapper">
<select id="getAll" resultType="com.potato.pojo.User">
select * from `user`
select>
<insert id="addUser" parameterType="com.potato.pojo.User">
insert into user (name, pwd, age) values (#{name},#{pwd},#{age});
insert>
<delete id="deleteUserById" parameterType="int">
delete from user where id = #{id}
delete>
<update id="updateUserById" parameterType="map">
update user set name = #{name} ,pwd = #{pwd} where id = #{id};
update>
mapper>
UserMapper.java
package com.potato.mapper;
import com.potato.pojo.User;
import java.util.List;
import java.util.Map;
/**
* @description
* @author: 土豆
* @create: 2020-05-30 15:37
**/
public interface UserMapper {
List<User> getAll();
int addUser(User user);
int deleteUserById(Integer id);
int updateUserById(Map map);
}
UserMapperTest.java
package com.potato.mapper;
import com.potato.pojo.User;
import com.potato.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
public class UserMapperTest {
//查
@Test
public void selectUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getAll();
userList.forEach(System.out::println);
sqlSession.close();
}
//增
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setName("王二小");
user.setPwd("456");
user.setAge(18);
int num = mapper.addUser(user);
System.out.println(num);
sqlSession.commit();
sqlSession.close();
}
//删
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int num = mapper.deleteUserById(4);
System.out.println(num);
sqlSession.commit();
sqlSession.close();
}
//删
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put("id",8);
map.put("name","胡爱国");
map.put("pwd","qwer");
map.put("age",18);
int num = mapper.updateUserById(map);
System.out.println(num);
sqlSession.commit();
sqlSession.close();
}
}
第一种:使用$
字符串拼接的方式,存在sql注入风险的方法:
<select id="likeUserByNameToString" parameterType="String" resultType="com.potato.pojo.User">
select * from user alias where alias.name like '%${name}%';
select>
测试
//模糊查询 有sql注入风险
@Test
public void likeUserByNameToString(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//我们拼接一sql 可以看结果:
List<User> userList = mapper.likeUserByNameToString("二%' or id like '%1");
userList.forEach(System.out::println);
sqlSession.close();
}
/* 结果不但把 name 中有二的数据查出来了,还把id为1开头的查出来了,这样做极其不安全
sql: select * from user where name like '%二%' or id like '%1%';
==> User(id=1, name=张三, pwd=123, age=18)
==> User(id=9, name=王二小, pwd=456, age=18)
*/
}
第二种:使用#
的方式,但是要记得#
方法不能字符串拼接 也就是不能为: “%#{name}%”
<select id="likeUserByNameToString" parameterType="String" resultType="com.potato.pojo.User">
select * from user alias where alias.name like #{name};
select>
测试
//模糊查询 倒是没有sql注入风险,但是麻烦
@Test
public void likeUserByNameToString2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.likeUserByNameToString2("%二%");
userList.forEach(System.out::println);
sqlSession.close();
}
/* 结果查询出来的没问题,但是很麻烦,而且总不能一直手动拼接吧
sql: select * from user alias where alias.name like ?;
==> Parameters: %二%(String)
==> User(id=9, name=王二小, pwd=456, age=18)
*/
}
第三种方法:使用mysql 的拼接方法 CONCAT('%','二','%')
,这种方法是最好的解决方案。
<select id="likeUserByNameToString3" parameterType="String" resultType="com.potato.pojo.User">
select * from user alias where alias.name like CONCAT('%',#{name},'%');
select>
测试
//模糊查询
@Test
public void likeUserByNameToString3(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.likeUserByNameToString3("二");
userList.forEach(System.out::println);
sqlSession.close();
}
mybatis-config.xml 文件
<configuration>
<properties resource="db.properties" />
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
<environment id="production">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<package name="com.potato.mapper">package>
mappers>
configuration>
1、配置文件的配置要遵循一下顺序
properties
==>settings
==>typeAliases
==>typeHandlers
==>objectFactory
==>
objectWrapperFactory
==>reflectorFactory
==>plugins
==>environments
==>
databaseIdProvider
==>mappers
2、外部properties文件的引入
例子:按照配置顺序,引入数据源的配置,在environments
数据源使用 ${xx}
引入即可
<properties resource="db.properties" />
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://39.105.27.58/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT
username=root
password=lovehxp521..
3、实体类别名
我们在mapper.xml文件中 返回类型每次都是用全路径名不不方便,导致代码的冗余。所以我们配置实体类别名
第一种方式:配置单个类
<typeAliases>
<typeAlias alias="User" type="com.potato.pojo.User"/>
typeAliases>
第二种方式:包扫描
<typeAliases>
<package name="com.potato.pojo">package>>
typeAliases>
mapper.xml
<select id="getAll" resultType="user">
select * from `user`
select>
第三种:使用@Alias
注解
@Alias("user")
public class User {
...
}
三种方式都可以,第二种我们使用的最多,如果想自定义别名时可以使用注解,或者在配置文件中,单个配置
4、设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
官网:https://mybatis.org/mybatis-3/zh/configuration.html#settings
比较重要的几个:
5、映射器(mappers)
作用:将接口方法和sql语句绑定
实现方式有四种:
常用的有2种(不常用的就不在解释,官网有):
通过映射文件的资源引用
<mappers>
<mapper resource="com/potato/mapper/UserMapper.xml">mapper>
mappers>
通过包扫描的方式,注意通过包扫描的方式必须 接口
和xml映射文件
必须同包且同名
<mappers>
<package name="com.potato.mapper">package>
mappers>
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)
SqlSessionFactory
一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory
被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
每个线程都应该有它自己的 SqlSession
实例。SqlSession
的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession
实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession
实例的引用放在任何类型的托管作用域中,比如 Servlet
框架中的 HttpSession
。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession
放在一个和 HTTP
请求相似的作用域中。 换句话说,每次收到 HTTP
请求,就可以打开一个 SqlSession
,返回一个响应后,就关闭它。 这个关闭操作很重要。
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):
cache
– 该命名空间的缓存配置。cache-ref
– 引用其它命名空间的缓存配置。resultMap
– 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。sql
– 可被其它语句引用的可重用语句块。insert
– 映射插入语句。update
– 映射更新语句。delete
– 映射删除语句。select
– 映射查询语句。实体类的属性名
和数据库的字段名
不一致时,结果映射不上去怎么解决?创建一个新的表:book
USE mybatis;
CREATE TABLE `book`(
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
book_name VARCHAR(255) NOT NULL,
book_pic DOUBLE NOT NULL DEFAULT 0,
book_author VARCHAR(255) NOT NULL DEFAULT '未知作者'
)ENGINE = INNODB DEFAULT CHARACTER SET = utf8;
INSERT INTO `book`(book_name,book_pic,book_author)
VALUES
('海王是怎么炼成的',99.5,'小黄'),
('渣男必备攻略',56.5,'小绿'),
('舔狗从入门到应有尽有!',180.0,'小黄·终极之作');
创建相应的实体类,并且使其价格字段和数据库不一致
@Data
public class Book {
private Integer id;
private String bookName;
private Double showPic;//showPic 这里和数据库的不一致,其他的因为开启了驼峰命名所以是可以映射上去的
private String bookAuthor;
}
bookMapper.xml
<mapper namespace="com.potato.mapper.BookMapper">
<select id="getAll" resultType="book">
select id, book_name, book_pic, book_author from book
select>
mapper>
bookMapper.java
public interface BookMapper {
List<Book> getAll();
}
测试-结果:
public class BookMapperTest {
@Test
public void getAll(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
List<Book> bookList = mapper.getAll();
bookList.forEach(System.out::println);
sqlSession.close();
}
/*
==> Preparing: select id, book_name, book_pic, book_author from book
==> Parameters:
<== Columns: id, book_name, book_pic, book_author
<== Row: 1, 朝花夕拾, 59.6, 鲁迅
<== Row: 2, 浮生六记, 49.5, 沈复
<== Row: 3, 济南的冬天, 48, 老舍
<== Total: 3
Book(id=1, bookName=朝花夕拾, showPic=null, bookAuthor=鲁迅)
Book(id=2, bookName=浮生六记, showPic=null, bookAuthor=沈复)
Book(id=3, bookName=济南的冬天, showPic=null, bookAuthor=老舍)
我们发现showPic并没有映射上结果,结果其实是查询出来的
*/
}
MySQL的结果集映射时按照输出的列名进行映射的,我们可以通过给sql 字段 添加别名进行映射。
<select id="getAll" resultType="book">
select id, book_name, book_pic as showPic, book_author from book
select>
再次测试,不需要修改java代码
public class BookMapperTest {
@Test
public void getAll(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
List<Book> bookList = mapper.getAll();
bookList.forEach(System.out::println);
sqlSession.close();
}
/*
==> Preparing: select id, book_name, book_pic as showPic, book_author from book
==> Parameters:
<== Columns: id, book_name, showPic, book_author
<== Row: 1, 朝花夕拾, 59.6, 鲁迅
<== Row: 2, 浮生六记, 49.5, 沈复
<== Row: 3, 济南的冬天, 48, 老舍
<== Total: 3
Book(id=1, bookName=朝花夕拾, showPic=59.6, bookAuthor=鲁迅)
Book(id=2, bookName=浮生六记, showPic=49.5, bookAuthor=沈复)
Book(id=3, bookName=济南的冬天, showPic=48.0, bookAuthor=老舍)
这两样是可以的,但是这样做如果字段多了很麻烦而且不太聪明。小学生都会的东西
*/
}
constructor
- 用于在实例化类时,注入结果到构造方法中
idArg
- ID 参数;标记出作为 ID 的结果可以帮助提高整体性能arg
- 将被注入到构造方法的一个普通结果id
– 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
result
– 注入到字段或 JavaBean 属性的普通结果
association
– 一个复杂类型的关联;许多结果将包装成这种类型
resultMap
元素,或是对其它结果映射的引用collection
– 一个复杂类型的集合
resultMap
元素,或是对其它结果映射的引用discriminator
– 使用结果值来决定使用哪个
resultMap
case
– 基于某些值的结果映射
case
也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射1、修改mapper.xml
,将返回结果改为 resultMap
<mapper namespace="com.potato.mapper.BookMapper">
<resultMap id="bookMap" type="book">
<id column="id" property="id">id>
<result column="book_name" property="bookName">result>
<result column="book_pic" property="showPic">result>
<result column="book_author" property="bookAuthor">result>
resultMap>
<select id="getAll" resultMap="bookMap">
select id, book_name, book_pic, book_author from book
select>
mapper>
测试-结果
public class BookMapperTest {
@Test
public void getAll(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
List<Book> bookList = mapper.getAll();
bookList.forEach(System.out::println);
sqlSession.close();
}
/*
==> Preparing: select id, book_name, book_pic, book_author from book
==> Parameters:
<== Columns: id, book_name, book_pic, book_author
<== Row: 1, 朝花夕拾, 59.6, 鲁迅
<== Row: 2, 浮生六记, 49.5, 沈复
<== Row: 3, 济南的冬天, 48, 老舍
<== Total: 3
Book(id=1, bookName=朝花夕拾, showPic=59.6, bookAuthor=鲁迅)
Book(id=2, bookName=浮生六记, showPic=49.5, bookAuthor=沈复)
Book(id=3, bookName=济南的冬天, showPic=48.0, bookAuthor=老舍)
结果还是能映射上去,这样一个简单的映射就完成了
*/
}
创建一个老婆表,咳咳,有缺老婆的和我说,给你们添加一个
USE mybatis;
CREATE TABLE `wife` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`name` VARCHAR ( 255 ) CHARACTER
SET utf8 COLLATE utf8_bin NOT NULL,
`age` INT ( 200 ) NULL DEFAULT 0,
`like` VARCHAR ( 255 ) CHARACTER
SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`user_id` INT ( 11 ) NOT NULL,
PRIMARY KEY ( `id` ) USING BTREE,
INDEX `user_id` ( `user_id` ) USING BTREE,
CONSTRAINT `user_id` FOREIGN KEY ( `user_id` ) REFERENCES `mybatis`.`user` ( `id` ) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8;
INSERT INTO `wife`
VALUES
( 1, '翠花', 18, '钻戒', 1 ),
( 2, '王大宝', 32, '金子', 2 ),
( 3, '郝美丽', 22, '跑车', 3 ),
( 5, '胡丽丽', 22, '花', 2 );
我们通过第一次查询用户的信息,然后在通过用户的字段再去查询他老婆的数据。
缺点:多次查询,性能差,非常不推荐。不做案例
修改实体类,在不改变原有的代码下添加一个老婆属性
@Data
public class User {
private Integer id;
private String name;
private String pwd;
private Integer age;
//包装类 存放自己的老婆
private Wife wife;
}
UserMapper.xml
<mapper namespace="com.potato.mapper.UserMapper">
<resultMap id="UserAndWifeMap" type="user">
<id column="id" property="id" />
<result column="name" property="name"/>
<result column="pwd" property="pwd"/>
<result column="age" property="age"/>
<association property="wife" javaType="wife">
<id column="w_id" property="id"/>
<result column="w_name" property="name"/>
<result column="w_age" property="age"/>
<result column="w_like" property="like"/>
<result column="u_id" property="userId"/>
association>
resultMap>
<select id="getUserAndWife" resultMap="UserAndWifeMap">
SELECT
u.id,
u.`name`,
u.pwd,
u.age,
w.id AS w_id,
w.`name` w_name,
w.age w_age,
w.`like` w_like,
w.user_id u_id
FROM
`user` u
LEFT JOIN `wife` w
ON
u.id = w.user_id
select>
mapper>
测试类
//查询用户和他老婆,左连接
@Test
public void selectUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserAndWife();
userList.forEach(System.out::println);
sqlSession.close();
}
/* 可以看出,使用左连接查询,左表中的数据都查出来了,和它相关的 wife表字段也都查询出来
User(id=1, name=张三, pwd=123, age=18, wife=Wife(id=1, name=翠花, age=18, like=钻戒, userId=1), likeBooks=null)
User(id=2, name=李四, pwd=456, age=24, wife=Wife(id=2, name=王大宝, age=32, like=金子, userId=2), likeBooks=null)
User(id=3, name=王五, pwd=789, age=20, wife=Wife(id=3, name=郝美丽, age=22, like=跑车, userId=3), likeBooks=null)
User(id=9, name=王二小, pwd=456, age=18, wife=Wife(id=5, name=胡丽丽, age=22, like=花, userId=9), likeBooks=null)
User(id=5, name=邓泉, pwd=147, age=16, wife=null, likeBooks=null)
User(id=8, name=胡爱国, pwd=qwer, age=28, wife=null, likeBooks=null)
User(id=10, name=胡大鹏, pwd=258, age=55, wife=null, likeBooks=null)
*/
查询用户喜欢的书有哪一些,我们创建一个用户书籍关联表
create table user_like_books
(
id int auto_increment
primary key,
user_id int not null,
book_id int not null
)
comment '用户喜欢的书籍 ';
-- 随便导入一些数据
修改User实体类,添加一个Book的集合的成员变量
@Data
public class User {
private Integer id;
private String name;
private String pwd;
private Integer age;
//包装类 存放自己的老婆
private Wife wife;
//包装类,每个用户都有积极喜欢的书籍,不只一本
private List<Book> likeBooks;
}
写mapper接口和sql文件,还有最重要的映射 resultMap
<resultMap id="UserAndBooks" type="user">
<id column="id" property="id" />
<result column="name" property="name"/>
<result column="pwd" property="pwd"/>
<result column="age" property="age"/>
<collection property="likeBooks" ofType="book">
<id column="book_id" property="id" />
<result column="book_name" property="bookName"/>
<result column="book_pic" property="showPic"/>
<result column="book_author" property="bookAuthor"/>
collection>
resultMap>
<select id="selectUserAndBooks" resultMap="UserAndBooks">
SELECT
u.*,
b.id book_id,
b.book_name,
b.book_pic,
b.book_author
FROM
`user` u
LEFT JOIN user_like_books ub ON u.id = ub.user_id
LEFT JOIN book b ON ub.book_id = b.id
select>
测试
//一对多 三表联查
@Test
public void selectUserAndBooks(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.selectUserAndBooks();
userList.forEach(System.out::println);
sqlSession.close();
}
/* 全部都查询出来了
User(id=1, name=张三, pwd=123, age=18, wife=null, likeBooks=[Book(id=1, bookName=朝花夕拾, showPic=59.6, bookAuthor=鲁迅), Book(id=2, bookName=浮生六记, showPic=49.5, bookAuthor=沈复)])
User(id=2, name=李四, pwd=456, age=24, wife=null, likeBooks=[Book(id=2, bookName=浮生六记, showPic=49.5, bookAuthor=沈复)])
User(id=3, name=王五, pwd=789, age=20, wife=null, likeBooks=[Book(id=3, bookName=济南的冬天, showPic=48.0, bookAuthor=老舍)])
User(id=5, name=邓泉, pwd=147, age=16, wife=null, likeBooks=[Book(id=4, bookName=海王是怎么炼成的, showPic=99.5, bookAuthor=小黄), Book(id=5, bookName=渣男必备攻略, showPic=56.5, bookAuthor=小绿)])
User(id=8, name=胡爱国, pwd=qwer, age=28, wife=null, likeBooks=[Book(id=5, bookName=渣男必备攻略, showPic=56.5, bookAuthor=小绿)])
User(id=9, name=王二小, pwd=456, age=18, wife=null, likeBooks=[Book(id=6, bookName=舔狗舔到最后应有尽有!, showPic=180.0, bookAuthor=小黄·终极之作)])
User(id=10, name=胡大鹏, pwd=258, age=55, wife=null, likeBooks=[])
*/