2020-08-26 myBatis 第三方框架集成

[if !supportLists]1. [endif]spring 集成myBatis

[if !supportLists]2. [endif]动态化SQL与脚本解析器



一、spring 集成myBatis

核心使用:

基础集成使用:

1、配置 SqlSessionFactoryBean

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

    <property name="dataSource" ref="dataSource"/>

</bean>


2、配置 MapperFactoryBean

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

    <property name="mapperInterface" value="com.tuling.mybatis.dao.UserMapper"/>

    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>

</bean>


 3、获取mapper 对像执行业务方法

context = new ClassPathXmlApplicationContext("spring.xml");

UserMapper mapper = context.getBean(UserMapper.class);

System.out.println(mapper.selectByid(1));


对像说明:

FactoryBean:

工厂Bean 用于 自定义生成Bean对像,当在ioc 中配置FactoryBean 的实例时,最终通过bean id 对应的是FactoryBean.getObject()实例,而非FactoryBean 实例本身

SqlSessionFactoryBean:

生成SqlSessionFactory 实例,该为单例对像,作用于整个应用生命周期。常用属性如下:

[if !supportLists]à [endif]dataSource:   数据源(必填)

[if !supportLists]à [endif]configLocation:指定mybatis-config.xml 的内容,但其设置的 将会失效(选填)

[if !supportLists]à [endif]mapperLocations:指定mapper.xml 的路径,相当于mybatis-config.xml 中 元素配置,(选填)

MapperFactoryBean:

生成对应的Mapper对像,通常为单例,作用于整个应用生命周期。常用属性如下:

[if !supportLists]à [endif]mapperInterface:mapper 接口      (必填)

[if !supportLists]à [endif]sqlSessionFactory:会话工厂实例引用(必填)

关于Mapper 单例情况下是否存在线程安全的问题?

在原生的myBatis 使用中mapper 对像的生命期是与SqlSession同步的,不会存在线程安全问题,现在单例的mapper 是如何解决线程安全的问题的呢?


核心流程解析:

SQL session 集成结构:



初始化流程

// 创建 会话模板 SqlSessionTemplate

>org.mybatis.spring.mapper.MapperFactoryBean#MapperFactoryBean()

> org.mybatis.spring.support.SqlSessionDaoSupport#setSqlSessionFactory

> org.mybatis.spring.SqlSessionTemplate#SqlSessionTemplate()

>org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor 


// 创建接口

> org.mybatis.spring.mapper.MapperFactoryBean#getObject

> org.mybatis.spring.SqlSessionTemplate#getMapper

>org.apache.ibatis.session.Configuration#getMapper


// 执行查询

>com.tuling.mybatis.dao.UserMapper#selectByid

 >org.apache.ibatis.binding.MapperProxy#invoke

 >org.mybatis.spring.SqlSessionTemplate#selectOne(java.lang.String)

 >org.mybatis.spring.SqlSessionTemplate#sqlSessionProxy#selectOne(java.lang.String)

 >org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke

 >org.mybatis.spring.SqlSessionUtils#getSqlSession()

 >org.apache.ibatis.session.SqlSessionFactory#openSession()

org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne()


每次查询都会创建一个新的SqlSession 会话,一级缓存还会生效吗?

通过前几次课我们了解到一级缓存的条件是必须相同的会话,所以缓存通过和spring 集成之后就不会生效了。除非使用spring 事物 这时就不会在重新创建会话。

事物使用:

spring 事物没有针对myBatis的配置,都是一些常规事物配置:

<!--添加事物配置-->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <constructor-arg ref="dataSource"/>

</bean>

<!--事物注解配置-->

<tx:annotation-driven/>


添加事物注解:

@Transactional()

public User getUser2(Integer id) {

    userMapper.selectByid(id);

    return userMapper.selectByid(id);

}


执行测试发现当调用getUser2 方法时两次查询不在重复创建 sqlSession。而是共用一个直到getUser2 方法结束。


事物与SqlSession 集成原理:

其原理前面讲查询流程时有所涉及。每次执行SQL操作前都会通过 getSqlSession 来获取会话。其主要逻辑是 如果当前线程存在事物,并且存在相关会话,就从ThreadLocal中取出 。如果没就从创建一个 SqlSession 并存储到ThreadLocal 当中,共下次查询使用。

相关源码:

org.mybatis.spring.SqlSessionUtils#getSqlSession()

org.springframework.transaction.support.TransactionSynchronizationManager#getResource

org.mybatis.spring.SqlSessionUtils#sessionHolder

org.apache.ibatis.session.SqlSessionFactory#openSession()

org.mybatis.spring.SqlSessionUtils#registerSessionHolder

org.springframework.transaction.support.TransactionSynchronizationManager#isSynchronizationActive

org.springframework.transaction.support.TransactionSynchronizationManager#bindResource

简化Mapper 配置

如果每个mapper 接口都配置MapperFactoryBean 相当麻烦可以通过如下配置进行自动扫描

 <mybatis:scan base-package="com.tuling.mybatis.dao"/>


其与spring bean 注解扫描机制类似,所以得加上注解扫描开关的配置

<context:annotation-config/>

二、动态化SQL

动态命令使用:

[if !supportLists]l [endif]if

[if !supportLists]l [endif]choose (when, otherwise)

[if !supportLists]l [endif]trim (where, set)

[if !supportLists]l [endif]foreach

<trim>示例说明:

<trim prefix="where" prefixOverrides="and|or">

    <if test="id != null">

        and id = #{id}

    </if>

    <if test="name != null">

        and name = #{name}

    </if>

</trim>

trim属性说明:

[if !supportLists]à [endif]prefix="where"   // 前缀

[if !supportLists]à [endif]prefixOverrides="and|or"  // 前缀要替换的词

[if !supportLists]à [endif]suffix=""   // 添加后缀

[if !supportLists]à [endif] suffixOverrides="" // 后缀要替换的词

<where>元素说明:

在where 包裹的SQL前会自动添加 where 字符 并去掉首尾多佘的 and|or 字符 相当于下配置:

 <trim prefix="where" prefixOverrides="and|or" suffixOverrides="and|or"> 

<set>元素说明:

在set包裹的SQL前会自动添加 set 字符并去掉首尾多佘的 , 字符。


<sql> 元素说明:

在同一个mapper  多个statement 存在多个相同的sql  片段时,可以通过元素声明,在通过    元素进行引用

声明sql 段

<sql id="files">

    id ,name ,createTime

</sql>


引用

<include refid="files" />


<bind> 变量使用

有时需要进行一些额外逻辑运行,通过声明元素,并在其value 属性中添加运算脚本,如下示例 自动给likeName 加上了% 分号,然后就可以用#{likeName} 来使用带%分号的like 运算。

<bind name="likeName" value="'%'+ _parameter.getName() +'%'"></bind>

内置变量

_databaseid  数据库标识ID

_parameter 当前参数变理


自定义模板解释器:

以上的if trim where 等逻辑符都是 myBatis 自带的XMLLanguageDriver 所提供的解释语言,除此之外 我们还可以使用 MyBatis-Velocity 或 mybatis-freemarker 等外部 解释器来编写动态脚本。


mybatis-freemarker 使用

引入mybatis 包:

<dependency>

    <groupId>org.mybatis.scripting</groupId>

    <artifactId>mybatis-freemarker</artifactId>

    <version>1.1.2</version>

</dependency>


添加sql 语句

<select id="selectByIds"

        resultType="com.tuling.mybatis.dao.User"

        lang="org.mybatis.scripting.freemarker.FreeMarkerLanguageDriver">

    select  * from user

    where  id in(${ids?join(',')})

</select>


添加接口方法

List<User> selectByIds(@Param("ids") List<Integer> ids);

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342