草庐IT

Mybatis多表关联查询(一对多关联查询)

暖锋丫 2023-08-01 原文

1、Mybatis一级缓存与二级缓存

目的:提高查询效率,降低数据库查询压力,提升系统整体性能。

一级缓存:默认开启,Session级别,同一个会话内生效。

命中缓存的情况:statementid、SQL语句、结果集的范围、传递的参数相同。

同一个查询之前执行DML操作,清空缓存,session.clearCache()也会清空缓存。

二级缓存:需要配置,SQLSessionFactory级别,不同会话之间可以共享。

使用步骤:1、全局配置mybatis_config.xml文件中

<settting name="cacheEnabled" value="true" />

2、mapper.xml配置要使用二级缓存的查询

<cache />

3、使用查询返回的对象的类必须实现序列化接口。

MemCached、OSCache、EHCache。

2、Mybatis一对一关联查询

<association>标签是处理单一的关联对象(处理单一属性的关联关系)。

property :指定关联对象的属性

javaType :关联对象的类型(可以省略)

select :执行一个新的查询

column:在新的查询中用哪个列的值作为查询条件

2.1 RolesMapper.java

提供一个根据用户主键userid去查询用户角色的方法,如下:

public interface RolesMapper {
    /**
     * 根据用户id查询此用户对应的角色信息
     * @param id
     * @return
     */
    Roles findRolesByUserId(int id);
}

2.2 RolesMapper.xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTDMapper3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dyh.dao.RolesMapper">
	<!--<resultMap id="rolesMap" type="com.dyh.pojo.Roles">
		<id property="roleid" column="roleid" />
		<result property="roleName" column="rolename" />
	</resultMap>-->
	<!--<select id="findRolesByUserId" resultMap="rolesMap" parameterType="int">-->
	<select id="findRolesByUserId" resultType="roles" parameterType="int">
		select roleid,rolename from roles where user_id=#{userid}
	</select>
</mapper>

2.3 JUnit单元测试RolesMapperTest

package com.dyh.test;

import com.dyh.dao.RolesMapper;
import com.dyh.pojo.Roles;
import com.dyh.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.*;

public class RolesMapperTest {
    SqlSession session;
    RolesMapper mapper;

    @Before
    public void setUp() throws Exception {
        session = MybatisUtil.getConnection();
        mapper = session.getMapper(RolesMapper.class);
    }

    @Test
    public void testFindRolesByUserId(){
        Roles roles = mapper.findRolesByUserId(1);
        System.out.println(roles);
    }

    @After
    public void tearDown() throws Exception {
        MybatisUtil.closeConnection();
    }
}

2.4 UserMapper.java

增加如下方法:

public interface UsersMapper {
    List<Users> queryUsersAndRoles();
    // 增加如下方法
    List<Users> queryUsersAndRolesBySelect();
}

2.5 UserMapper.xml

增加如下内容:

<resultMap id="usersAndRolesMap2" type="users">
		<id property="userid" column="userid" />
		<result property="username" column="username" />
		<result property="usersex" column="usersex" />
		<!-- 配置一对一的关联关系 -->
		<!-- column="userid" 是users表中的主键,使用这个值取查询roles表 -->
		<association property="roles" javaType="roles"
					 select="com.dyh.dao.RolesMapper.findRolesByUserId" column="userid">
			<id property="roleid" column="roleid" />
			<result property="roleName" column="rolename" />
		</association>
	</resultMap>

	<sql id="deptColumns">
		deptno,dname,loc as city
	</sql>

	<select id="queryUsersAndRolesBySelect" resultMap="usersAndRolesMap2">
		SELECT u.userid,u.username,u.usersex
		FROM users u
	</select>

2.6 JUnit单元测试UsersMapperTest.java

 @Test
    public void testQueryUsersAndRoles2(){
        List<Users> list = mapper.queryUsersAndRolesBySelect();
        list.forEach(System.out::println);
    }

 

2.7 延迟加载与立即加载

在association一对一关联标签和collection一对多关联标签中有个属性fetchType="lazy",属性值有lazy懒加载(延迟加载)、eager立即加载。如果不配置fetchType属性值,fetchType默认值是eager立即加载。

2.7.1 懒加载(延迟加载)lazy

测试类UsersMapperTest.java中修改代码如下:注意,不能直接打印users对象,因为其toString方法中获取了roles的属性值。

 @Test
    public void testQueryUsersAndRoles2(){
        List<Users> list = mapper.queryUsersAndRolesBySelect();
        //list.forEach(System.out::println);
        for (Users users:list) {
            System.out.println(users.getUsername());
            // 懒加载没有获取角色信息的时候,不会去查询角色表
            //System.out.println(users.getRoles());
        }
    }

UserMapper.xml配置修改如下:

 

 

 

 

 

一、一对多关联查询

应用场景:完成用户与订单查询。 要求一个用户可以对应多个订单。

1、collection标签

<collection>标签是处理所关联对象是多个的(处理关联属性是集合时的关联关系)。

property :指定关联对象的属性

javaType :关联对象的类型(可省略。默认List 类型,如果集合是 Set 类型时需要配置并给定 Set 的全名 )

ofType:指定集合里存放的对象类型

select :执行一个新的查询

column:在新的查询中用哪个列的值作为查询条件

2、建表orders

-- users表使用上次课建立好的表和数据
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;

INSERT INTO orders VALUES(DEFAULT, 80, 1),
(DEFAULT, 90, 1),
(DEFAULT, 100, 1),
(DEFAULT, 92, 2),
(DEFAULT, 102, 2);
SELECT * FROM orders;

-- 一对多查询,查询用户及其对应的订单信息
SELECT u.userid,u.username,u.usersex,
	o.orderid,o.orderprice
FROM users u,orders o
WHERE u.userid=o.user_id

 

3、Orders实体类

public class Orders {
    private Integer orderid;
    private Double orderprice;
	// get、set、toString、constructor方法自行补充
}

4、修改Users实体类

一对多,说明一个users对象可以有多个订单,所以要在Users类中添加如下属性:

  private List<Orders> ordersList;

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", usersex='" + usersex + '\'' +
                ", roles=" + roles +
                ",orderList=" + ordersList +
                '}';
    }

5、修改UsersMapper.java

  /**
     * 查询用户和其所下的订单
     * @return
     */
    List<Users> queryUsersAndOrders();

6、修改UsersMapper.xml

<resultMap id="usersAndOrdersMap" type="com.dyh.pojo.Users">
		<id property="userid" column="userid" />
		<result property="username" column="username" />
		<result property="usersex" column="usersex" />
		<!-- 配置一对多的关联关系 -->
		<collection property="ordersList" ofType="com.dyh.pojo.Orders" >
			<id property="orderid" column="orderid" />
			<result property="orderprice" column="orderprice" />
		</collection>
	</resultMap>
	<sql id="deptColumns">
		deptno,dname,loc as city
	</sql>

	<select id="queryUsersAndOrders" resultMap="usersAndOrdersMap">
		SELECT u.userid,u.username,u.usersex,
			o.orderid,o.orderprice
		FROM users u,orders o
		WHERE u.userid=o.user_id
	</select>

7、测试UsersMapperTest.java

增加如下方法:

 @Test
    public void testQueryUsersAndOrders(){
        List<Users> list = mapper.queryUsersAndOrders();
        list.forEach(System.out::println);
    }

二、一对多查询实现方式二

1、UsersMapper.java

中增加如下方法:

  /**
     * 查询用户和其所下的订单
     * @return
     */
    List<Users> queryUsersAndOrders2();

 

2、UserMapper.xml

中增加如下代码:

<resultMap id="usersAndOrdersMap2" type="com.dyh.pojo.Users">
		<id property="userid" column="userid" />
		<result property="username" column="username" />
		<result property="usersex" column="usersex" />
		<!-- 配置一对多的关联关系 -->
		<collection property="ordersList" ofType="com.dyh.pojo.Orders"
					select="com.dyh.dao.OrdersMapper.findOrderListByUsersId" column="userid">
			<id property="orderid" column="orderid" />
			<result property="orderprice" column="orderprice" />
		</collection>
	</resultMap>
	<sql id="deptColumns">
		deptno,dname,loc as city
	</sql>

	<select id="queryUsersAndOrders2" resultMap="usersAndOrdersMap2">
		SELECT u.userid,u.username,u.usersex
		FROM users u
	</select>

需要增加com.dyh.OrdersMapper.findOrderListByUsersId的接口及实现。

3、OrdersMapper.java

public interface OrdersMapper {
    /**
     * 根据用户id去查询用户的所有订单
     * @param userid        用户id
     * @return              订单集合
     */
    List<Orders> findOrderListByUsersId(int userid);
}

4、OrdersMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTDMapper3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dyh.dao.OrdersMapper">
	<select id="findOrderListByUsersId"
			resultType="com.dyh.pojo.Orders" parameterType="int">
		select orderid,orderprice from orders where user_id=#{userid}
	</select>
</mapper>

5、JUnit单元测试UsersMapperTest.java

增加如下代码:

 @Test
    public void testQueryUsersAndOrders2(){
        List<Users> list = mapper.queryUsersAndOrders2();
        list.forEach(System.out::println);
    }

测试结果

一对一的实现方式二:<association select="" />

延迟加载与立即加载:<association fetchType="lazy|eager" />

一对多关联查询:<collection ofType="集合中的对象类型" />

 

有关Mybatis多表关联查询(一对多关联查询)的更多相关文章

  1. ruby-on-rails - 如何添加具有额外列的多对多记录 - 2

    我有以下模型用户has_many:users_contactshas_many:contacts,through::users_contactsaccepts_nested_attributes_for:contacts,allow_destroy:true联系方式has_many:users_contactshas_many:users,through::users_contactsaccepts_nested_attributes_for:users_contacts,allow_destroy:true用户联系belongs_to:usersbelongs_to:contacts

  2. ruby - Datamapper 中多对多关系的战略性预加载? - 2

    我正在使用DataMapper,一个用于ruby​​的开源ORM,我很想抓挠。目前,DataMapper可以对一对多关系使用StrategicEagerLoading(SEL),但不能对发生N+1查询的多对多关系使用。我想设法让这项工作正常进行,但我找不到在哪里做。所以两部分问题:如何运行测试套件,以便它显示失败(注意,现在所有应该失败的规范都标记为待定)?在何处以及如何为一对多关系实现SEL? 最佳答案 对于第二个问题,您可以尝试深入研究代码:/lib/dm-core/associations/relationship.rb#Ea

  3. ruby-on-rails - 为什么 Rails 中的 ActiveRecord 不支持多表继承? - 2

    我试图实现一组我放在纸上的模型,但遇到了一个问题,我认为最好的解决方法是使用多表继承设置。然而,在谷歌搜索后我发现ActiveRecord不支持MTI......尽管有很多文章展示了如何做到这一点。这让我想知道如果没有实现我是否正确设置了我的模型。所以我的问题是为什么ActiveRecord没有内置对MTI的支持?如果您对我的模型设置“将会”是什么样子感到好奇,我会把它留在下面。classPlayer其中玩家可以是CollegePlayer和ProPlayer之一或两者。或者在另一个例子中......classPerson“人”可以是用户、前玩家和/或教练。

  4. ruby-on-rails - Rails 一对一关系 - 2

    我有以下内容:classUser'Car',:foreign_key=>'user_id'classCar'User',:foreign_key=>'user_id'它基本上是用户和汽车之间的一对一关系。我想要的是让用户能够拥有一辆且只有一辆汽车。这意味着如果他创造了一辆分配给他的汽车,他将无法创造第二辆。这是怎么做到的? 最佳答案 当然有几种不同的方法可以实现这一点。我建议在该表上创建一个复合键索引,以确保user_id在表中是唯一的。这将确保它只会出现一次。在迁移中,您可以这样写。add_index(:cars,:worker_

  5. ruby-on-rails - Rails/postgres, 'foreign keys' 存储在数组中以创建一对多关联 - 2

    可以使用postgres数组在rails(4)中创建一对多/has_many关联吗?我知道外键类型数组是不可能的。示例:一项任务有多个受让人。传统上我会使用关联表来解决这个问题:tasks->assignees->users。使用数组,这将不是必需的,因为可以存储多个“外键”。然后可以使用以下查询来获取分配给我的所有任务:select*fromtaskswhere?INtasks.assignees 最佳答案 您将无法让Rails识别此数组并将其用于关联。但是如果您想要更快地搜索/过滤分配给用户的任务,您可以在任务对象中保留一个用户

  6. ruby-on-rails - Rails (ActiveRecord) 多对多表 - 2

    我有两个模型,用户和组。每个组可以有多个用户,每个用户可以在多个组中。我目前有一些简单的东西,比如:用户:has_many:groups组:has_many:users所以我有一个groups_users表,它只是用group_id和user_id创建行。我想为此添加另一列(我有),问题是如何在不使用自定义SQL调用的情况下从模型访问它?在组模型中,我可以使用self.users,在用户中,我可以使用self.groups有没有办法从用户模型更改此表中的第三列?对不起,如果这令人困惑,请就此提出建议 最佳答案 这里有一些教程应该会有

  7. ruby - 将字符串拆分为 Ruby 中的一对字符 - 2

    我有一个字符串(例如“AABBCCDDEEFF”),我想将其拆分为一个数组,每个元素包含两个字符-["AA","BB","CC","DD","EE","FF"]. 最佳答案 试试String对象的scan方法:>>foo="AABBCCDDEEFF"=>"AABBCCDDEEFF">>foo.scan(/../)=>["AA","BB","CC","DD","EE","FF"] 关于ruby-将字符串拆分为Ruby中的一对字符,我们在StackOverflow上找到一个类似的问题:

  8. javascript - 如何从 JavaScript 中同一对象中的另一个方法调用方法? - 2

    我刚刚开始使用OOjavascript,所以请多多包涵。这个有效:varmyObj={foo:function(){alert('hello');this.bar();},bar:function(){alert('world');}}但是,如果我在“foo”方法中的hello警报之后做了一些其他事情,那么“this”的含义将从对象变为我上次选择的任何内容,因此使用this.bar()不执行类中的其他方法。所以我尝试将“this”缓存在一个变量中,如下所示:varmyObj={publicVars:{theObj:this},foo:function(){alert('hello');

  9. javascript - Sequelize.js 插入一个具有一对多关系的模型 - 2

    我有两个具有一对多关系的Sequelize模型。我们称它们为所有者和属性(property)。假设它们是使用sails-hook-sequelize本身定义的(简化)。//Owner.jsmodule.exports={options:{tableName:'owner'},attributes:{id:{type:Sequelize.BIGINT,allowNull:false,primaryKey:true,autoIncrement:true},name:{type:Sequelize.STRING(255)},associations:function(){Owner.hasM

  10. javascript - 在一对多关系中删除实体的正确方法 - 2

    我有一个父子关系(一对多)。我能够创建child,但删除失败。我创建了一个child,保存它,但是当我删除时,我得到:Aforeignkeyvaluecannotbeinsertedbecauseacorrespondingprimarykeyvaluedoesnotexist.[Foreignkeyconstraintname=FK_dbo.Children_dbo.Parents_ParentId]我确实注意到,当删除被发送到服务器时,子项的parentid为0,实体状态为“已修改”。我希望这会被“删除”。相关View模型部分:functionqueryFailed(error){

随机推荐