一、MyBatis连接池及事务控制

1、连接池

在实际开发中,都会使用连接池,因为它可以减少获取连接缩消耗的时间。所谓连接池,就是存储数据库连接的容器。连接池中存储一定数量的数据库连接,当线程需要使用到连接时,就从连接池中获取数据库连接,线程使用完数据库连接会还回连接池中。

连接池:其实就是一个集合对象,该集合必须是线程安全的;而且线程必须实现对列,满足 ” 先进先出 “ 的特性

2、MyBatis中的连接池

三种配置方式

配置位置:MyBatis主配置文件中,<dataSource> 元素;type属性的值表示采用何种连接池;

  • POOLED:采用传统的 javax.sql.DataSource 接口规范中的连接池,MyBatis中有该规范的实现;

  • UNPOOLED:采用传统获取数据库连接的方式,虽然实现了 javax.sql.DataSource 接口,但没有连接池的思想——即需要时才创建数据库连接;

  • JNDI:采用服务器提供的 JNDI 技术实现,来获取 DataSource 对象,不同服务器的拿到的 DataSource 对象是不同的;

    注意:不是 web 或 maven 工程,是不能使用的。Tomcat 服务器中,采用连接池是 dbcp 连接池

3、事务

什么是事务?

事物的四大特性ACID

不考虑隔离性会产生的3个问题

解决方法:四种隔离级别

MyBatis 中的事务控制默认没有开启自动提交,可以使用 SqlSessionFactory.opensession(boolean autoCommit) 方法创建设置是否开启自动提交事务的 Sqlsession 对象。但有一点需要注意的是:开启了自动提交事务,MyBatis是对一个数据库操作(并非多个)进行事务提交。没有开启自动提交事务时,是使用 SqlSession 对象的 commit 方法 和 rollback 方法进行事务的提交的回滚。

二、动态SQL语句

1、参数传递

  • 单参数——定义传入参数的类型,可以是基本类型、引用类型、映射;

    • 直接使用映射的 key 值:#{key},该 key 值可以不与方法的参数名匹配;
  • 多参数——需要在接口类中的抽象方法的参数前使用注解 @Param("") 指定参数名;

    • 使用 #{索引}、#{param+数字} 指定参数;
    • 在SQL语句中,使用 #{参数名} 、或 #{param+数字} 指定参数;
    <!--接口方法:User findUser(String username, String password); -->
    
    <select id="findUser" resultType="*.user">
    select * from user where username=#{0} and password=#{1}
    </select>
    <!--User findUser(@Param("username") String username, @Param("password") String password);-->
    
    <select id="findUser" resultType="user">
    select * from user where username=#{username} and password=#{password} </select>

2、MyBatis标签

  1. if 标签:用于进行条件判断, test 属性用于指定判断条件。为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条件

    <select id="sel" resultType="user">
    select * from user where 1=1
    <if test="username != null and username != ''">
    and username=#{username}
    </if>
    <if test="password != null and password != ''">
    and password=#{password}
    </if>
    </select>
  2. choose(when otherwise)标签:这是一套标签, 功能类似于 switch...case...

    <select id="sel" resultType="user">
    select * from user
    <where>
    <choose>
    <when test="username != null and username != ''">
    and username = #{username}
    </when>
    <when test="password != null and password != ''">
    and password = #{password}
    </when>
    <otherwise>
    and 1=1
    </otherwise>
    </choose>
    </where>
    </select>
  3. where/set标签
    • 用于管理 where 子句,有如下功能:

      1. 如果没有条件, 不会生成 where 关键字;
      2. 如果有条件, 会自动添加 where 关键字;
      3. 如果第一个条件中有 and 关键字, 去除之;
      <select id="sel" resultType="user">
      select * from user
      <where>
      <if test="username != null and username != ''">
      and username=#{username}
      </if>
      <if test="password != null and password != ''">
      and password=#{password}
      </if>
      </where>
      </select>
    • 用于维护 update 语句中的 set 子句,功能如下:

      1. 满足条件时, 会自动添加 set 关键字;
      2. 会去除 set 子句中多余的逗号;
      3. 不满足条件时, 不会生成 set 关键字;
      <update id="updUser" parameterType="user">
      update user
      <set>
      id=#{id},
      <!-- 防止所有条件不成立时的语法错误 -->
      <if test="username != null and username != ''">
      username=#{username},
      </if>
      <if test="password != null and password != ''">
      password=#{password},
      </if>
      </set>
      where id=#{id}
      </update>
  4. trim() 标签:用于在前后添加或删除一些内容

    • prefix:在前面添加内容;
    • prefixOverrides:从前面去除内容;
    • suffix:向后面添加内容;
    • suffixOverrides:从后面去除内容;
    <update id="updUser" parameterType="user">
    update user
    <!-- prefix: 前缀, 表示向前面添加内容
    prefixOverrides: 从前面删除内容
    suffix: 后缀, 表示向后面添加内容
    suffixOverrides: 从后面删除内容 -->
    <trim prefix="set" prefixOverrides="user" suffix="hahah" suffixOverrides=",">
    username=#{username},
    </trim>
    where id=#{id}
    </update>
  5. bind标签:用于对数据进行再加工。比如,模糊查询中对数据的拼接

    <select id="sel" resultType="user">
    select * from user
    <where>
    <if test="username!=null and username!=''">
    <bind name="username" value="'%' + username + '%'"/>
    and username like #{username}
    </if>
    </where>
    </select>
  6. foreach标签:用于在 SQL 语句中遍历集合参数, 在 in 查询中使用

    • collection: 待遍历的集合;
    • open: 设置开始符号;
    • item: 迭代变量;
    • separator: 项目分隔符;
    • close: 设置结束符号;
    <select id="selIn" parameterType="list" resultType="user">
    select * from user
    <where>
    <foreach collection="list" open="id in (" separator="," close=")" item="item">
    #{item}
    </foreach>
    </where>
    </select>
  7. sql/include标签<sql> 用于提取 SQL 语句, <include>用于引用 SQL 语句

    <sql id="mySql">
    select * from user
    </sql> <select id="selIn" parameterType="list" resultType="user">
    <include refid="mySql"/>
    from t_user where id in
    <foreach collection="list" open="(" separator="," close=")" item="item">
    #{item}
    </foreach>
    </select>

三、MyBatis的延迟加载

问题:在一对多中,当我们有一个用户,它有100个账户。1)当查询用户时,要不要把关联的账户查出来?2)当查询账户时,要不要把关联的用户查出来?

一对多的关系中,Java 中是使用集合来存储多的一方,如果,仅仅只想查询用户信息,并不关心其账户的信息,这时,如果还将该用户下的所有账户查询出来,不仅影响效率,也占用内存。

什么是延时加载(懒加载)?——在真正使用数据时才发起查询,不使用时不查询,也就是:按需查询。

什么是立即加载?——不管用不用,只要一调用方法,就发起查询。

何时使用延时加载,何时使用立即加载?——一对多、多对多:通常采用延时加载;多对一,一对一:通常采用立即加载;

延时加载实现

在 mapping 配置文件中,配置 resultMap 元素,在需要使用延迟加载的对象使用 <association> 元素或 collection 元素关联;并通过以下属性,引用查询语句和传递查询条件,MyBatis会将查询结果封装到延迟加载的对象:

  • select:查询语句;
  • column:查询语句的条件;

但这还没有启用懒加载方式。需要启用懒加载方式,在主配置文件 <settings> 元素中配置以下 setting 子元素:

<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • lazyLoadingEnabled:全局启用或禁用延迟加载。当禁用时, 所有关联对象都会即时加载。 默认值:(true|false)
  • aggressiveLazyLoading:当启用时, 有延迟加载属性的对象在被调用时将会完全加载任意属性。否则, 每种属性将会按需要加载。 默认值:(true|false)

在没有启用延迟加载时,MyBatis会加载所有查询数据;启用延迟加载时,当延迟加载的对象被调用,才会加载;

四、MyBatis缓存机制

什么是缓冲?——存储在内存中的临时数据;

为什么使用缓冲?——减少和数据库的交互次数,提高执行效率;

什么数据能使用缓存,什么数据不能?

  • 适用于缓存:经常查询且不常改变、数据的正确与否对最终结果影响不大;
  • 不适用缓存:经常改变的数据、数据的正确与否对最终结果影响很大;比如:商品的库存,银行的汇率,股市的牌价等;

一级缓存和二级缓存

  1. 一级缓存

    指的是 MyBatis 中 SqlSession 对象的缓存。

    当执行查询之后,查询结果会同时存入到 SqlSession 提供的一个 Map 区域中;当再次查询相同的数据时,MyBatis 会先去 Map 区域中查找,没有找到在执行查询操作。当 SqlSession 对象消失或清空缓存操作时,一级缓存也就消失了

    如何保证数据库数据和一级缓存数据保持一致(数据同步)?

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

  2. 二级缓存

    指的是 MyBatis 中 SqlSessionFactory 对象的缓存,有同一个 SqlSessionFactory 对象创建并共享缓存。

    二级缓存的使用步骤

    1. 让 MyBatis 支持二级缓存(在主配置文件中配置);

      <settings>
      <setting name="cacheEnabled" value="true"/>
      </settings>
    2. 让当前映射文件支持二级缓存(在 mapper 配置文件配置);

      <cache/>
    3. 让当前操作支持二级缓存(select 元素中配置)

      <select id="findAll"resultMap="user" useCache="true">
      select * from class
      </select>

    二级缓存中存放的内容是数据,而不是对象

五、注解开发

当使用注解开发时,相同包名下不能有 mapper 配置文件,会发生配置文件解析冲突错误。

1、增删改查

  1. @Select()
  2. @Delete()
  3. @Update()
  4. @Insert()

2、POJO类属性名与列名不一致

  1. 定义属性名与列名映射

    @Results(id="UserMap",value={
    @Result(id=true,column="",property=""),
    @Result(column="",property=""),
    @Result(column="",property=""),
    })
  2. 引用映射,引用 @Results 中的 ID 值

    @ResultMap(value={"UserMap"})

3、多表查询

  1. 一对一

    @Results(id="UserMap",value={
    @Result(id=true,column="",property=""),
    @Result(column="",property=""),
    @Result(column="",property=""),
    @Result(column="作为查询的列名",property="属性名",
    one=@One(
    select="全限定查询方法"
    fetchType=FetchType.EAGER
    ))
    })

    使用 @One 注解定义查询方法,根据 column 中的属性作为查询条件,返回一条数据;

    • select:查询语句(包名.类名.方法名);
    • fetchType:加载方式;FetchType对象的 LAZY(延迟加载)、EAGER(立即加载)、DEFAULT
  2. 一对多

    @Results(id="UserMap",value={
    @Result(id=true,column="",property=""),
    @Result(column="",property=""),
    @Result(column="",property=""),
    @Result(column="作为查询的列名",property="属性名",
    many=@Many(
    select="全限定查询方法"
    fetchType=FetchType.LAZY
    ))
    })

4、开启二级缓存

  1. 在主配置文件中配置开启二级缓存;

    <settings>
    <setting name="cacheEnabled" value="true"/>
    </settings>
  2. 在接口类级别上使用 @CacheNamespace(blocking= true)

MyBatis基础_连接池与事务、动态SQL、注解开发的更多相关文章

  1. MyBatis基础入门《二十》动态SQL(foreach)

    MyBatis基础入门<二十>动态SQL(foreach) 1. 迭代一个集合,通常用于in条件 2. 属性 > item > index > collection : ...

  2. MyBatis基础入门《十九》动态SQL(set,trim)

    MyBatis基础入门<十九>动态SQL(set,trim) 描述: 1. 问题 : 更新用户表数据时,若某个参数为null时,会导致更新错误 2. 分析: 正确结果: 若某个参数为nul ...

  3. MyBatis基础入门《十八》动态SQL(if-where)

    MyBatis基础入门<十八>动态SQL(if-where) 描述: 代码是在<MyBatis基础入门<十七>动态SQL>基础上进行改造的,不再贴所有代码,仅贴改动 ...

  4. Mybatis连接池及事务

    一:Mybatis连接池 我们在学习WEB技术的时候肯定接触过许多连接池,比如C3P0.dbcp.druid,但是我们今天说的mybatis中也有连接池技术,可是它采用的是自己内部实现了一个连接池技术 ...

  5. 【MyBatis】MyBatis 连接池和事务控制

    MyBatis 连接池和事务控制 文章源码 MyBaits 连接池 实际开发中都会使用连接池,因为它可以减少获取连接所消耗的时间.具体可查看 MyBatis 数据源配置在 SqlMapConfig.x ...

  6. 阶段3 1.Mybatis_07.Mybatis的连接池及事务_3 mybatis连接池的分类

    2.mybatis中的连接池     mybatis连接池提供了3种方式的配置:         配置的位置:             主配置文件SqlMapConfig.xml中的dataSourc ...

  7. 《深入理解mybatis原理3》 Mybatis数据源与连接池

    <深入理解mybatis原理> Mybatis数据源与连接池 对于ORM框架而言,数据源的组织是一个非常重要的一部分,这直接影响到框架的性能问题.本文将通过对MyBatis框架的数据源结构 ...

  8. Spring Boot1.5.4 连接池 和 事务

    原文:https://github.com/x113773/testall/issues/10 默认连接池---spring Boot中默认支持的连接池有Tomcat.HikariCP .DBCP . ...

  9. Java基础-DBCP连接池(BasicDataSource类)详解

    Java基础-DBCP连接池(BasicDataSource类)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程 ...

随机推荐

  1. javascript数组大全(一张图列出数组的所有方法)

    把所有数组的方法列在了一张图上,为了自己温故一下,也为了以后忘记时好查阅. 如果大家在上面查阅方法,可以找到对应的方法名,看前面简单的注释,还是不能明白的话,可以看一下官网说明,地址给大家列出来,MD ...

  2. ReentrantLock 源码分析从入门到入土

    回答一个问题 在开始本篇文章的内容讲述前,先来回答我一个问题,为什么 JDK 提供一个 synchronized 关键字之后还要提供一个 Lock 锁,这不是多此一举吗?难道 JDK 设计人员都是沙雕 ...

  3. keuectl命令

    Kubernetes命令行 kubectl用于运行Kubernetes集群命令的管理工具 kubectl命令行语法 kubectl [command] [TYPE] [NAME] [flags] co ...

  4. array_diff 大bug

    $aa = array("手机号", "first","keyword1","keyword2","keywo ...

  5. 11.在Chrome谷歌浏览器中安装插件XPath Helper的方法

    1.首先在以下链接下载XPath Helper插件,链接:https://pan.baidu.com/s/1Ng7HAGgsVfOyqy6dn094Jg 提取码:a1dv 2.插件下载完成后解压,然后 ...

  6. Asp.Net Core下的开源任务调度平台ScheduleMaster

    从何说起 2017年初的时候,由于当时项目需要做了一个乞丐版定时调度系统,那时候只在单机上实现了核心的调度功能.做这个玩意之前也调研了社区中开源的解决方案,找了几个实地部署试跑了一下,其实都很不错.但 ...

  7. 日志查看工具 logviewer pro的使用

    1.logViewer Pro 介绍 logViewer Pro 是一款log文件查看器,它可以在短短数秒内打开上G的LOG文件,支持高亮某行文字(例如警告,错误),支持Unicode名字,支持查看的 ...

  8. Qt5学习(2)

    1.学习了qt quick application 这是一种跟application不同的设计方式.主要就是靠“拖拖拽拽”,然后设置属性(颜色,大小),布局(margins等),然后要注意控件的从属关 ...

  9. try catch 自定义捕获异常

    当我们完成一个程序时,如果没有异常捕获的话,用户使用时会出现许多bug.而加入异常捕获之后便会提醒用户使用时避免产生不必要的错误.具体操作实现如下: 首先创造一个MyException类,继承自Exc ...

  10. postman传递当前时间戳

    有时我们在请求接口时,需要带上当前时间戳这种动态参数,那么postman能不能自动的填充上呢. 1请求动态参数(例如时间戳) 直接在参数值写 {{$timestamp}} 如下: 我们也可以使用pos ...