MyBatis-Spring官方文档 学习笔记

前言

之前也写过SpringMVC + MyBatis + Spring的小项目,但是对MyBatis的了解还是不够深入,配置也只会生搬硬套。刚好求职失败,遂有空,去阅读以下MyBatis-Spring的官方文档,深入学习一波。


什么是MyBatis-Spring?

MyBatis-Spring就是帮助你将MyBatis代码无缝的整合到Spring中。Spring将会加载必要的sqlSessionFactory类和session类。

配置数据源

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
           <list>
                <value>classpath:app.properties</value>
           </list>
        </property>
    </bean>
    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>

        <property name="maxPoolSize" value="20" />
        <property name="minPoolSize" value="5" />
        <property name="acquireIncrement" value="3" />
        <property name="initialPoolSize" value="5"></property>
    </bean>

配置SqlSessionFactory

我们需要在Spring应用上下文定义一个SqlSessionFactory和数据源dataSource。在MyBatis-Spring中,SqlSessionFacotoryBean调用其getObject()方法去创建SqlSessionFactory实例。创建SqlSessionFactory实例中用到了享元设计模式,是一个种结构型模式。

  • 享元模式(Flyweight Pattern):主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了极少对象数量从而改善应用所需的对象结构的方式。
    • 优点:大大减少对象的创建,降低系统的内存,提供效率。
    • 缺点: 提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部的状态而改变,否则会造成系统的混乱。

言归正传,首先在这个SqlSessionFactoryBean类中,调用getObject()时,会判断sqlSessionFacotory是否为空,如果不为空直接返回sqlSessionFacotory。如果为空,则调用afterPropertiesSet()方法。

public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }
    return this.sqlSessionFactory;
  }

afterPropertiesSet()会检查dataSourcesqlSessionFactoryBuilder是否为空。接着会调用buildSqlSessionFactory()方法。

  public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");

    this.sqlSessionFactory = buildSqlSessionFactory();
  }

buildSqlSessionFactory()方法会读取xml配置,然后创建sqlSessionFactory实例。

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
        //...省略几百行代码
    return this.sqlSessionFactoryBuilder.build(configuration);
  }

言归正传,配置如下:

  • mapperLocations: 我们存放MyBatismapper.xml文件路径。
  • typeAliasesPackage:一般对应着我们实体类所在的包。多个package之间可以用逗号或者分号等来进行分隔。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliasesPackage" value="com.helping.wechat.model"></property>
        <property name="mapperLocations" value="classpath*:com/helping/wechat/model/**/mysql/*Mapper.xml" />
</bean>

事务

一个使用MyBatis-Spring的主要原因是它允许MyBatis参与到Spring的事务管理中,而不是给MyBatis创建一个新的事务管理器。MyBatis-Spring利用了存在Spring中的org.springframework.jdbc.datasource.DataSourceTransactionManager。我们可以通过配置<tx:annotation-driven transaction-manager="transactionManager"/>来使用@Transactional注解面对切面编程。同时我们也可以通常的AOP来配置Service层的事务。在事务处理期间,一个单独的SqlSession对象将会被创建和使用,当事务完成时,这个Session就会以合适的方式进行提交和回滚。具体配置如下:

 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
</bean>
    
<!-- 当Service层的方法不是以delete,insert,update,save方法开头时,发生异常时无法进行事务回滚
        但是可以通过@Transactional注解在类或者方法上,可以启动事务。
     -->
   <tx:annotation-driven transaction-manager="transactionManager"/>
   
    <!-- 任何RuntimeException将触发事务回滚,但是任何Checked Exception不会触发事务回滚 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="delete*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
            <tx:method name="insert*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
            <tx:method name="update*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
            <tx:method name="save*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <aop:pointcut expression="execution(* com.helping.wechat.service..*.*(..))" id="pc"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pc" order="1"/>
    </aop:config>

使用SqlSession

  • MyBatis中,我们可以使用SqlSessionFactory来创建SqlSession。一旦获得了一个session之后,我们可以使用它来执行映射语句,提交或者回滚。当我们不需要它的时候,我们可以关闭session

  • 而在MyBatis-Spring之后,你不再需要SqlSessionFactory了,我们的Dao层可以注入一个线程安全的SqlSession,然后进行提交或者回滚,最后关闭session

SqlSession Template

SqlSession TemplateMyBatis-Spring的核心,这个类负责MyBatisSqlSession

this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);

我们可以知道SqlSessionTemplate类的构造器第一个参数是SqlSessionFactory的实例。SqlSessionTemplate实现了SqlSession接口。

public class SqlSessionTemplate implements SqlSession {
//...省略n行
}

之前的我是这样配置的:

<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>

    <bean id="baseDao" abstract="true">
        <property name="sqlSessionTemplate" ref="sqlSessionTemplate" />
    </bean>
    
    <bean id="adminUserDao" class="com.helping.wechat.dao.admin.mybatis.AdminUserDao" parent="baseDao" />

其实没有必要去Spring.xml去配置Dao层,Service层,Controller类。可以用注解代替,后面会讲到。对了,SqlSessionTemplate其实也不需要配,SqlSession我们可以通过new SqlSessionTemplate()创建出来。

SqlSessionDaoSupport

SqlSessionDaoSupport是一个抽象的支持类,为你提供SqlSession。我们自定义的Dao层的实现类继承它就行了。调用getSession()做你想要的。SqlSessionDaoSupport内部实现:

public abstract class SqlSessionDaoSupport extends DaoSupport {

  private SqlSession sqlSession;

  private boolean externalSqlSession;

  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
  }

  public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    this.sqlSession = sqlSessionTemplate;
    this.externalSqlSession = true;
  }

  /**
   * Users should use this method to get a SqlSession to call its statement methods
   * This is SqlSession is managed by spring. Users should not commit/rollback/close it
   * because it will be automatically done.
   *
   * @return Spring managed thread safe SqlSession
   * 返回线程安全的sqlSession
   */
  public SqlSession getSqlSession() {
    return this.sqlSession;
  }

  /**
   * {@inheritDoc}
   */
  protected void checkDaoConfig() {
    notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
  }
}

看到getSession()方法的注释写着,用户不应该去提交,回滚,或者关闭session的操作,因为session会自动关闭它。这个方法返回的是一个线程安全的sqlSession


使用注解代替XML的配置

如果不使用注解,你的Spring.xml配置肯定是多的爆炸,比如这样:

<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>

    <bean id="baseDao" abstract="true">
        <property name="sqlSessionTemplate" ref="sqlSessionTemplate" />
    </bean>
    
    <bean id="adminUserDao" class="com.helping.wechat.dao.admin.mybatis.AdminUserDao" parent="baseDao" />

    <bean id="adminUserService" class="com.helping.wechat.service.admin.impl.AdminUserService" >
        <property name="adminUserDao" ref="adminUserDao" />
    </bean>

    <bean id="adminUserController" class="com.helping.wechat.controller.admin.AdminUserController" >
        <property name="adminUserService" ref="adminUserService" />
    </bean>
    
    <bean id="ordinaryUserDao" class="com.helping.wechat.dao.admin.mybatis.OrdinaryUserDao" parent="baseDao" />
    
    <bean id="ordinaryUserService" class="com.helping.wechat.service.admin.impl.OrdinaryUserService" >
        <property name="ordinaryUserDao" ref="ordinaryUserDao" />
    </bean>

    <bean id="ordinaryUserController" class="com.helping.wechat.controller.admin.OrdinaryUserController" >
        <property name="ordinaryUserService" ref="ordinaryUserService" />
    </bean>

如果使用了@Service@Component@Repository@Controller@Resource@Autowired 这些注解,这些配置统统可以不要。首先要在SpringMVC.xml配置自动扫描注解的tag

<context:component-scan base-package="com.helping.wechat.controller" />
        <context:component-scan base-package="com.helping.wechat.handler" />
        <context:component-scan base-package="com.helping.wechat.dao" />
        <context:component-scan base-package="com.helping.wechat.service" />
  • @Service用于标注业务Service层的类上,有value这个属性。
@Service(value = "adminUserService")
public class AdminUserService implements IAdminUserService {

    @Resource(name = "adminUserDao")
    private IAdminUserDao adminUserDao;
}
  • @Controller用于标注控制Controller层的类上。
@Controller
@RequestMapping("/api/admin")
public class AdminUserController extends BaseController {

    @Resource(name = "adminUserService")
    private IAdminUserService adminUserService;
}
  • @Repository用于标注在Dao层的类上,有value这个属性。
@Repository(value = "adminUserDao")
public class AdminUserDao extends SqlSessionDaoSupport implements IAdminUserDao {

}
  • @Component就是把类注册到Spring.xml文件中。
@Component
public abstract class BaseDao {
    protected SqlSession sqlSession;

    protected SqlSessionFactory sqlSessionFactory;

    @Resource(name = "sqlSessionFactory")
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
        this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }

    public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    public SqlSession getSqlSession() {
        return sqlSession;
    }
}

Dao层的类继承它就行了,就可以调用getSqlSession()进行想要的操作了。

  • @Resource默认按名称进行装配字段或者setter方法。名称可以通过name属性进行指定,如果没有指定name属性。当注解写在字段上,默认按字段名进行安装名称查找,如果注解写在setter方法上,默认按属性名进行装配,当找不到与名称相匹配的bean时候,才会按照类型进行装配。如果name属性指定了,那么就只能按名称进行装配了。
@Service(value = "adminUserService")
public class AdminUserService implements IAdminUserService {

    @Resource(name = "adminUserDao")
    private IAdminUserDao adminUserDao;
}
  • @Autowired:默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要运行null值,可以设置它的required属性为false。如果我们想要使用名称进行装配,可以结合@Qualifier注解使用。
    @Autowired
    public void setAdminUserService(IAdminUserService adminUserService) {
        this.adminUserService = adminUserService;
    }

尾言

明天去看看通用MapperpageHelper怎么配置。晚安,地球人。

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

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,423评论 0 4
  • 单独使用mybatis是有很多限制的(比如无法实现跨越多个session的事务),而且很多业务系统本来就是使用sp...
    七寸知架构阅读 3,428评论 0 53
  • Spring 技术笔记Day 1 预热知识一、 基本术语Blob类型,二进制对象Object Graph:对象图...
    OchardBird阅读 961评论 0 2
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,736评论 6 342