一、搭建环境
1、创建项目
2、添加jar包
3、创建实体
public class Users {
private int userid;
private String username;
private String usersex;
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
@Override
public String toString() {
return "Users{" +
"userid=" + userid +
", username='" + username + '\'' +
", usersex='" + usersex + '\'' +
'}';
}
}
4、创建properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc.mysql://localhost:3306/bjsxt
jdbc.username=root
jdbc.password=mysql
5、添加工具类
public class MybatisUtils {
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
private static SqlSessionFactory sqlSessionFactory = null;
static{
//创建SqlSessionFactory
InputStream is = null;
try{
is = Resources.getResourceAsStream("mybatis-cfg.xml");
}catch (IOException e){
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
}
//获取SqlSession
public static SqlSession getSqlSession(){
SqlSession sqlSession = threadLocal.get();
if(sqlSession == null){
sqlSession = sqlSessionFactory.openSession();
threadLocal.set(sqlSession);
}
return sqlSession;
}
//关闭SqlSession
public static void closeSqlSession(){
SqlSession sqlSession = threadLocal.get();
if(sqlSession != null){
sqlSession.close();
threadLocal.set(null);
}
}
}
6、创建全局配置文件
<?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>
<!-- 引入properties属性文件-->
<properties resource="db.properties"/>
<!-- 配置别名-->
<typeAliases>
<package name="com.bjsxt.pojo"/>
</typeAliases>
<!-- 配置环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 引入映射配置文件-->
<mappers>
<package name="com.bjsxt.mapper"/>
</mappers>
</configuration>
7、创建映射配置文件
<?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.bjsxt.mapper.UsersMapper">
</mapper>
二、手动处理映射关系
resultMap 标签是 Mybatis 最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。
1、resultMap 的基础使用场景
在 Mybatis 中如果查询的结果集的列名与 POJO 的属性名相同,那么我们是不需要在Mybatis 中配置映射关系的,但是当查询到的结果集的列名与 POJO 的属性名不匹配时,Mybatis 是无法完成影射处理的。
解决方案:
- 通过定义列别名的方式来解决该问题。
- 通过在 resultMap 标签中定义映射关系来解决该问题。
2、通过 resultMap 标签解决实体与结果集的映射
2.1、 修改映射配置文件
<resultMap id="usersMapper" type="com.bjsxt.pojo.Users">
<id property="userid" column="id"/>
<result property="username" column="name"/>
<result property="usersex" column="sex"/>
</resultMap>
<select id="selectUsersAll" resultMap="usersMapper">
select userid as id,username as name,usersex as sex from users
</select>
2.2、 修改 UsersMapper 接口
public interface UsersMapper {
List<Users> selectUsersAll();
}
2.3、 创建测试类
public class SelectUsersAllTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
List<Users> list = usersMapper.selectUsersAll();
list.forEach(System.out::println);
}
}
三、 一对一的关联查询
1、标签
标签是处理单一的关联对象(处理单一属性的关联关系)。
property:指定关联对象的属性
javaType:关联对象的类型(可以省略)
select:执行一个新的查询
column:在新的查询中用哪个列的值作为查询条件
2、需求
完成用户与角色查询。要求一个用户只能对应一个角色。
3、创建 roles 表
CREATE TABLE `roles` (
`roleid` int(11) NOT NULL AUTO_INCREMENT,
`rolename` varchar(30) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`roleid`),
UNIQUE KEY `roles_fk` (`user_id`) USING BTREE,
CONSTRAINT `roles_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4、创建 Roles 实体
public class Roles {
private int roleid;
private String rolename;
public int getRoleid() {
return roleid;
}
public void setRoleid(int roleid) {
this.roleid = roleid;
}
public String getRolename() {
return rolename;
}
public void setRolename(String rolename) {
this.rolename = rolename;
}
@Override
public String toString() {
return "Roles{" +
"roleid=" + roleid +
", rolename='" + rolename + '\'' +
'}';
}
}
5、修改Users实体
public class Users {
private int userid;
private String username;
private String usersex;
private Roles roles;
public Roles getRoles() {
return roles;
}
public void setRoles(Roles roles) {
this.roles = roles;
}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
@Override
public String toString() {
return "Users{" +
"userid=" + userid +
", username='" + username + '\'' +
", usersex='" + usersex + '\'' +
'}';
}
}
6、修改映射配置文件
<!-- 一对一的关联查询映射-->
<resultMap id="usersAndRolesMapper" type="com.bjsxt.pojo.Users">
<id property="userid" column="userid"/>
<result property="username" column="username"/>
<result property="usersex" column="usersex"/>
<association property="roles" javaType="com.bjsxt.pojo.Roles">
<id property="roleid" column="roleid"/>
<result property="rolename" column="rolename"/>
</association>
</resultMap>
<select id="selectUsersAndRoles" resultMap="usersAndRolesMapper">
select * from users as u,roles as r where u.userid = r.user_id and u.userid = #{userid}
</select>
7、修改UsersMapper接口
Users selectUsersAndRoles(int userid);
8、创建测试类
public class SelectUsersAndRolesTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users = usersMapper.selectUsersAndRoles(1);
System.out.println(users);
Roles roles = users.getRoles();
System.out.println(roles);
}
}
9、运行结果
四、 一对多的关联查询
1、collection标签
2、需求
完成用户与订单查询。要求一个用户可以对应多个订单。
3、创建 Orders 表
CREATE TABLE `orders` (
`orderid` int(11) NOT NULL AUTO_INCREMENT,
`orderprice` double DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`orderid`),
KEY `orders_fk` (`user_id`),
CONSTRAINT `orders_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4、创建 Orders 实体
public class Orders {
private int orderid;
private double orderprice;
public int getOrderid() {
return orderid;
}
public void setOrderid(int orderid) {
this.orderid = orderid;
}
public double getOrderprice() {
return orderprice;
}
public void setOrderprice(double orderprice) {
this.orderprice = orderprice;
}
@Override
public String toString() {
return "Orders{" +
"orderid=" + orderid +
", orderprice=" + orderprice +
'}';
}
}
5、修改 Users 实体
public class Users {
private int userid;
private String username;
private String usersex;
private Roles roles;
private List<Orders> orders;
public List<Orders> getOrders() {
return orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
public Roles getRoles() {
return roles;
}
public void setRoles(Roles roles) {
this.roles = roles;
}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
@Override
public String toString() {
return "Users{" +
"userid=" + userid +
", username='" + username + '\'' +
", usersex='" + usersex + '\'' +
'}';
}
}
6、修改映射配置文件
<!-- 一对多映射关系-->
<resultMap id="usersAndOrdersMapper" type="com.bjsxt.pojo.Users">
<id property="userid" column="userid"/>
<result property="username" column="username"/>
<result property="usersex" column="usersex"/>
<collection property="orders" ofType="com.bjsxt.pojo.Orders">
<id property="orderid" column="orderid"/>
<result property="orderprice" column="orderprice"/>
</collection>
</resultMap>
<!-- 根据用户ID查询用户以及该用户所对应的所有订单-->
<select id="selectUsersAndOrders" resultMap="usersAndOrdersMapper">
select * from users as u,orders as o where u.userid = o.user_id and u.userid = #{userid}
</select>
7、修改 UsersMapper 接口
Users selectUsersAndOrders(int userid);
8、创建测试类
public class SelectUsersAndOrdersTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users = usersMapper.selectUsersAndOrders(1);
System.out.println(users);
List<Orders> list = users.getOrders();
list.forEach(System.out::println);
}
}
9、运行结果
五、 多对多的关联查询
1、需求
根据 ID 查询用户与订单以及订单中所包含的所有商品。
2、创建 items 表
CREATE TABLE `items` (
`itemid` int(11) NOT NULL AUTO_INCREMENT,
`itemname` varchar(255) DEFAULT NULL,
`itemprice` double DEFAULT NULL,
PRIMARY KEY (`itemid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
3、创建 orders_items 中间表
CREATE TABLE `orders_items` (
`order_id` int(11) NOT NULL,
`item_id` int(11) NOT NULL,
PRIMARY KEY (`order_id`,`item_id`),
KEY `order_item_fk2` (`item_id`),
CONSTRAINT `order_item_fk1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`orderid`),
CONSTRAINT `order_item_fk2` FOREIGN KEY (`item_id`) REFERENCES `items` (`itemid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4、创建 Items 实体
public class Items {
private int itemid;
private String itemname;
private double itemprice;
public int getItemid() {
return itemid;
}
public void setItemid(int itemid) {
this.itemid = itemid;
}
public String getItemname() {
return itemname;
}
public void setItemname(String itemname) {
this.itemname = itemname;
}
public double getItemprice() {
return itemprice;
}
public void setItemprice(double itemprice) {
this.itemprice = itemprice;
}
@Override
public String toString() {
return "Items{" +
"itemid=" + itemid +
", itemname='" + itemname + '\'' +
", itemprice=" + itemprice +
'}';
}
}
5、修改 Orders 实体
public class Orders {
private int orderid;
private double orderprice;
private List<Items> items;
public List<Items> getItems() {
return items;
}
public void setItems(List<Items> items) {
this.items = items;
}
public int getOrderid() {
return orderid;
}
public void setOrderid(int orderid) {
this.orderid = orderid;
}
public double getOrderprice() {
return orderprice;
}
public void setOrderprice(double orderprice) {
this.orderprice = orderprice;
}
@Override
public String toString() {
return "Orders{" +
"orderid=" + orderid +
", orderprice=" + orderprice +
'}';
}
}
6、修改映射配置文件
<!-- 多对多关联查询-->
<resultMap id="usersAndOrdersAndItems" type="com.bjsxt.pojo.Users">
<id property="userid" column="userid"/>
<result property="username" column="username"/>
<result property="usersex" column="usersex"/>
<collection property="orders" ofType="com.bjsxt.pojo.Orders">
<id property="orderid" column="orderid"/>
<result property="orderprice" column="orderprice"/>
<collection property="items" ofType="com.bjsxt.pojo.Items">
<id property="itemid" column="itemid"/>
<result property="itemname" column="itemname"/>
<result property="itemprice" column="itemprice"/>
</collection>
</collection>
</resultMap>
<!-- 根据用户ID查询用户与订单以及订单中所包含的商品-->
<select id="selectUsersAndOrdersAndItems" resultMap="usersAndOrdersAndItems">
select * from users as u,orders as o,orders_items as oi,items as i where u.userid = o.user_id and o.orderid = oi.order_id and oi.item_id = i.itemid and u.userid = #{userid}
</select>
7、修改 UsersMapper 接口
Users selectUsersAndOrdersAndItems(int userid);
8、创建测试类
public class SelectUsersAndOrdersAndItemsTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users = usersMapper.selectUsersAndOrdersAndItems(1);
System.out.println(users);
List<Orders> orders = users.getOrders();
for (Orders order :orders){
System.out.println(order);
List<Items> items = order.getItems();
items.forEach(System.out::println);
}
}
}
9、运行结果
六、 Mybatis 多表查询中的数据加载方式
1、多表查询 SQL 语句的写法
1.1、 连接查询
使用内连接或者外连接的方式查询数据。
优点:在一次查询中完成数据的查询操作。降低查询次数提高查询效率。
缺点:如果查询返回的结果集较多会消耗内存空间。
1.2、 N+1 次查询
分解式查询,将查询分解成多个 SQL 语句。
优点:配和着延迟加载可实现结果集分步获取,节省内存空间。
缺点:由于需要执行多次查询,相比连接查询效率低。
2、N+1 查询的加载方式
2.1、 立即加载
在一次查询中执行所有的 SQL 语句。
2.2、 延迟加载
在一次查询中执行部分 SQL 语句,根据操作映射的关联象触发其他查询。
3、MyBatis 的延迟加载看的使用
在 Mybatis 中可以使用延迟加载数据的策略实现对关联对象的查询。
使用延迟加载要求:
- 查询方式需要使用 N+1 次查询。
- 在映射配置文件或者全局配置文件中开启延迟加载。
3.1、开启延迟加载
3.2、 修改全局配置文件配置触发方法
<settings>
<setting name="lazyLoadTriggerMethods" value=""/>
</settings>
3.3、 修改映射配置文件
<!-- 延迟加载-->
<resultMap id="usersAndOrdersMapperLazy" type="com.bjsxt.pojo.Users">
<id property="userid" column="userid"/>
<result property="username" column="username"/>
<result property="usersex" column="usersex"/>
<collection property="orders" ofType="com.bjsxt.pojo.Orders" fetchType="lazy" select="selectOrdersByUserId" column="userid"/>
</resultMap>
<!-- 根据用户ID查询用户-->
<select id="selectUsersByIdLazy" resultMap="usersAndOrdersMapperLazy">
select * from users where userid = #{userid}
</select>
<!-- 根据用户ID查询订单-->
<select id="selectOrdersByUserId" resultType="com.bjsxt.pojo.Orders">
select * from orders where user_id = #{userid}
</select>
3.4、 修改 UsersMapper 接口
Users selectUsersByIdLazy(int userid);
3.5、 创建测试类
public class SelectUsersByIdLazyTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users = usersMapper.selectUsersByIdLazy(1);
System.out.println(users);
List<Orders> list = users.getOrders();
list.forEach(System.out::println);
}
}