03_Mybatis

本文深入探讨MyBatis框架的高级特性,包括事务控制、缓存机制、动态SQL、多表关联查询及延迟加载策略。通过具体示例,解析如何优化数据库交互,提升应用程序性能。

03_Mybatis

Mybatis事务控制

工程准备:新建一个Maven类型的module:实现Mybatis保存用户功能,便于基于该功能的代码程序说明Mybatis的事务控制

SqlMapConfig.xml中配置的type=“JDBC”:使用Jdbc的事务管理机制,connection的事务

Mybatis默认把Jdbc的事务自动提交给关闭了

Mybatis缓存

缓存只能对的是CRUD中的R(查询)

缓存需要进行维护(数据发生变化的时候,需要维护缓存),这样才能保持数据的一致性

工程准备:实现Mybatis根据id查询用户功能,便于基于该功能的代码程序说明Mybatis缓存

概述

网站性能优化第一定律:优先使用缓存机制(分布式redis缓存)。

Mybatis中的缓存

​ Mybatis提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。

​ Mybatis中缓存分为一级缓存,二级缓存。Mybatis的二级缓存机制存在诸多问题。无法在企业中开发中应用。

​ Mybatis的一级缓存是SqlSession级别(在同一个SqlSession持续期间有效)的缓存,是默认开启的

  @Test
    public void testQueryUserOrders() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 <!--一级缓存是SqlSession级别的,同一个SqlSession范围内执行相同的sql语句,会走一级缓存--> 
        sqlSession.close();

    }

结果分析

​ 虽然上面的代码我们查询中写了两次,但是只执行了一次数据库查询操作,这就是Mybatis提供给我们的一级缓存起作用了

​ 因为一级缓存的存在,导致第二次查询同一id的记录是(同一条sql),并没有发出sql语句从数据库中查询数据,而是从一级缓存中查询

​ 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库中查询信息。得到用户信息,将用户信息存储到一级缓存中,

​ 如果sqlSession去执行commit操作(执行插入,更新,删除),清空sqkSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

​ 一级缓存是SqlSession范围的缓存,当调用sqlSession的修改,添加,删除,commit(),close()等方法时候,就会清空一级缓存

Mybatis映射文件的Sql深入(动态sql机制)

优雅的帮助我们拼接sql语句(主要是标签是使用)

需求:根据用户性别和用户名称查询用户列表

if标签/where标签

   List<User>  queryUserByWhere(User user) throws Exception;
<!--根据用户性别和用户名查询user ,拼接sql语句的方式-->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
        SELECT * FROM USER
        <where><!--where会自动添加where关键字并且干掉紧接着的第一个and关键字或者or关键字-->
            <!--if标签会帮我们进行判断,test判断表达式的真假-->
            <if test="sex != null and sex != '' ">
                AND sex = #{sex}
            </if>
            <if test="username != null and username != ''">
                AND username=#{username}
            </if>
        </where>
    </select>
/**
     *使用if标签和where标签 动态SQL语句 拼接sql语句
     */
    @Test
    public void testQueryUserByWhere() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
//        user.setUsername("张三");
        user.setSex("1");
        List<User> users = mapper.queryUserByWhere(user);
        for (int i = 0; i < users.size(); i++) {
            User user1 =  users.get(i);
            System.out.println(user);
        }

        sqlSession.close();
    }

sql片段

<!--
        sql片段
        引用sql片段使用include标签,refid 只想sql片段的id 如果共享其他的mapper文件当中的sql片段,
        只要在refid前面加上另一个mapper映射文件的namespace即可
    -->
    <sql id="commentSql">
         id,username,sex,birthday,address
    </sql>

foreach标签

List<User> queryUserByIdsList(List<Integer> list)throws Exception;
 <select id="queryUserByIdsList" parameterType="list" resultType="user">
        SELECT <include refid="commentSql"></include> FROM USER
        <foreach collection="list" open="where id in(" close=")" separator="," item="item">
            #{item}
        </foreach>
    </select>
   /**
     * 根据多个id来查询用户列表
     */
    @Test
    public void testQueryUserByIdsList() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<Integer> list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        List<User> users = userMapper.queryUserByIdsList(list);
        for (int i = 0; i < users.size(); i++) {
            User user =  users.get(i);
            System.out.println(user);
        }

        sqlSession.close();

    }

Mybatis的多表关联查询

多表关系分析

多表:至少2两张表

多表关系分析技巧:盯着一张表A的一条记录,从这一条记录出发,看这条记录在另外一张表B中可能有几条关联记录,如果只会有一条关联记录,那么从A到B就是一对一,如果可能有多条关联记录,那么从A到B就是一个一对多的关系。

多表关系:

一对一

一对多

User表 orders表

从表中有外键指向主表中的主键

多对多

User role

中间表

Userid roleid

多表关联的SQL语句表达

  1. 笛卡尔积

    select * from user,orders

  2. 笛卡尔积 + where

    select * from user u ,orders o where u.id = o.user_id

  3. 关联查询

    内关联 inner join效果等同于笛卡尔积+where

    外关联

    ​ left join

    ​ right join

一对一查询

Mybatis 帮我们做的事:

  1. sql语句是用户自己写的,Mybatis框架只是帮我们执行
  2. 封装结果集

需求:查询订单表全部数据,关联查询出订单对应的用户数据(username address)

Mapper映射文件
<select id="queryOrdersUser" resultMap="ordersUserResultMap">
    SELECT
      o.`id`,
      o.`user_id`,
      o.`number`,
      o.`createtime`,
      o.`note`,
      u.`username`,
      u.`address`
    FROM
      orders o
      LEFT JOIN user u
        ON o.`user_id` = u.`id`
</select>


<resultMap id="ordersUserResultMap" type="orders">
    <!--两部分数据:订单+用户-->
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="number" property="number"/>
    <result column="createtime" property="createtime"/>
    <result column="note" property="note"/>

    <!--association:关联的意思,用于一对一关联封装数据
        property:一对一关联后封装成的数据所对应的属性名
        javaType:属性的类型
    -->
    <association property="user" javaType="user">
        <id column="user_id" property="id"/>
        <result column="username" property="username"/>
        <result column="address" property="address"/>
    </association>
</resultMap>

测试程序
@Test
public void testQueryOrdersUser()throws Exception {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
    List<Orders> ordersList = ordersMapper.queryOrdersUser();
    if(ordersList != null && ordersList.size() > 0) {
        for (int i = 0; i < ordersList.size(); i++) {
            Orders orders =  ordersList.get(i);
            System.out.println(orders);
        }
    }
    sqlSession.close();
}

一对多查询

需求:查询全部用户数据,关联查询出订单数据

Mapper映射文件
<!--一对多用例-->
<select id="queryUserOrders" resultMap="userOrdersResultmap">
    SELECT
      u.`id`,
      u.`username`,
      u.`sex`,
      u.`birthday`,
      u.`address`,
      o.`id` oid,
      o.`user_id`,
      o.`number`,
      o.`createtime`,
      o.`note`
    FROM
      user u
      LEFT JOIN orders o
        ON u.`id` = o.`user_id`
</select>

<resultMap id="userOrdersResultmap" type="user">
    <!--两部分数据:用户+订单-->
    <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="sex" property="sex"/>
    <result column="birthday" property="birthday"/>
    <result column="address" property="address"/>

    <!--一对多使用collection标签
        property:封装成对应的属性的属性名
        ofType:因为此时属性是一个list集合,collection已经表明了集合的意思,最重要的指定list里面的泛型类型,
        所以使用ofType
    -->
    <collection property="ordersList" ofType="orders">
        <id column="oid" property="id"/>
        <result column="user_id" property="userId"/>
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>
    </collection>
</resultMap>

多对多查询

多对多关系分析

实现Role到User的一对多

实现User到Role的一对多

Mybatis延迟加载策略

什么是延迟加载

Mybatis怎么实现Mybatis

了解(不推荐)Mybatis注解开发

使用注解实现基本的CRUD操作

使用注解实现复杂关系映射开发

使用注解实现一对一查询

使用注解实现一对多查询

【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺和拉格朗日的电动汽车优化调度(分时电价调度)(Matlab代码实现)内容概要:本文介绍了基于蒙特卡洛和拉格朗日方法的电动汽车充电站有序充电调度优化方案,重点在于采用分散式优化策略应对分时电价机制下的充电需求管理。通过构建数学模型,结合不确定性因素如用户充电行为和电网负荷波动,利用蒙特卡洛模拟生成大量场景,并运用拉格朗日松弛法对复杂问题进行分解求解,从而实现全局最优或近似最优的充电调度计划。该方法有效降低了电网峰值负荷压力,提升了充电站运营效率与经济效益,同时兼顾用户充电便利性。 适合人群:具备一定电力系统、优化算法和Matlab编程基础的高校研究生、科研人员及从事智能电网、电动汽车相关领域的工程技术人员。 使用场景及目标:①应用于电动汽车充电站的日常运营管理,优化充电负荷分布;②服务于城市智能交通系统规划,提升电网与交通系统的协同水平;③作为学术研究案例,用于验证分散式优化算法在复杂能源系统中的有效性。 阅读建议:建议读者结合Matlab代码实现部分,深入理解蒙特卡洛模拟与拉格朗日松弛法的具体实施步骤,重点关注场景生成、约束处理与迭代收敛过程,以便在实际项目中灵活应用与改进。
### Spring Boot与MyBatis集成时的Servlet.service()异常分析及解决方案 在Spring Boot与MyBatis集成的过程中,`Servlet.service()`异常通常由多种原因引发。以下是对该问题的详细分析及解决方法。 #### 1. 异常的根本原因 `Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception` 是一个常见的Spring Boot运行时错误提示,表明在处理请求时出现了异常。具体原因可能包括但不限于以下几种情况: - 数据库查询语法错误[^2]。 - Service层或Controller层未正确注入依赖[^3]。 - 跨域配置问题导致的异常[^4]。 - MyBatis映射文件中的SQL语句存在问题[^5]。 #### 2. 数据库查询语法错误 如果异常信息中包含 `org.springframework.jdbc.BadSqlGrammarException` 或 `java.sql.SQLSyntaxErrorException`,则表明SQL语句存在语法错误。例如,引用中提到的 `Unknown column 'is_deleted' in 'field list'` 表明数据库表中缺少 `is_deleted` 字段。此时需要检查以下内容: - 确保数据库表结构与SQL语句一致。 - 检查MyBatis映射文件中的SQL语句是否正确。 #### 3. 依赖注入问题 如果异常信息中包含 `java.lang.NullPointerException`,则可能是Service层或Controller层的依赖注入未正确完成[^3]。以下是常见问题及解决方法: - 确保所有需要注入的类都添加了正确的注解(如 `@Autowired` 或 `@Resource`)。 - 检查Spring Bean是否被正确扫描,确保相关类所在的包已被Spring Boot的组件扫描路径覆盖。 #### 4. 跨域配置问题 如果异常发生在跨域请求场景下,则可能是跨域配置不正确导致的问题[^4]。以下是一个典型的跨域配置示例: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true); } } ``` 确保上述配置已正确应用到项目中。 #### 5. MyBatis映射文件问题 如果异常信息中包含 `org.mybatis.spring.MyBatisSystemException`,则可能是MyBatis映射文件中的SQL语句存在问题[^5]。例如,引用中提到的批量插入方法: ```java int insertManyZmmo3110MaterialData(@Param("entities") List<TabZmmo3110MaterialData> entities); ``` 需要确保对应的XML映射文件中定义了正确的SQL语句。以下是一个批量插入的示例: ```xml <insert id="insertManyZmmo3110MaterialData" parameterType="java.util.List"> INSERT INTO tab_zmmo3110_material_data (column1, column2, column3) VALUES <foreach collection="entities" item="entity" separator=","> (#{entity.column1}, #{entity.column2}, #{entity.column3}) </foreach> </insert> ``` #### 6. 综合排查步骤 - 检查数据库表结构是否与SQL语句一致。 - 确保所有依赖注入均正确完成。 - 检查跨域配置是否正确应用。 - 验证MyBatis映射文件中的SQL语句是否正确。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值