Spring-与持久层整合

作者: zhl 分类: Spring 发布时间: 2023-11-02 21:23

一、持久层整合

Spring框架为什么要与持久层技术进行整合

  1. JavaEE开发需要持久层进行数据库的访问操作
  2. JDBC Hibernate MyBatis进行持久开发过程存在大量的代码冗余
  3. Spring基于模板设计模式对于上述的持久层技术进行了封装

Spring可以与哪些持久层技术进行整合?

  1. JDBC
    • JDBCTemplate
  2. Hibernate(JPA)
    • HibernateTemplate
  3. MyBatis
    • SqlSessionFactoryBean MapperScannerConfigure

二、Spring与MyBatis整合

Spring与MyBatis整合思路分析

Spring与MyBatis整合的开发步骤

  • 配置文件(applicationContext.xml)进行相关的配置
    <bean id="dataSource" class="">
    <!--创建SqlSessionFactory-->
    <bean id="ssfb" class="SqlSessionFactoryBean">
        <property name="dataSource" ref=""/>
        <property name="typeAliasesPackage">
            <!--指定实体类所在的包 com.mysite.entity -->
        </property>
        <property name="mapperLocations">
            <!--指定 配置文件(映射文件)的路径,com.mysite.mapper/*Mapper.xml-->        
        </property>
    </bean>
    <!--DAO接口的实现类
        SqlSession ->  sqlSession.getMapper()  ---- xxxDAO实现类对象
        XxxDao     ->  xxxDao
    -->
    <bean id="scanner" class="MapperScannerConfigure">
        <property name="sqlSessionFactoryBeanName" value="ssfb"/>
        <property name="basePackage" value="">
            <!--指定DAO接口的包 com.mysite.dao/mapper-->
        </property>
    </bean>

经常根据需求的开发步骤

  1. 实体
  2. 创建DAO接⼝
  3. 实现Mapper⽂件
  • 搭建开发环境(jar)
    <!--Spring与MyBatis整合-->
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.6</version>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.32</version>
    </dependency>
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.13</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.22</version>
    </dependency>
  • Spring文件的配置
    <!--配置文件参数化-->
    <context:property-placeholder location="classpath:/jdbc.properties"/>
    <!--连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="name" value="${jdbc.username}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--创建SqlSessionFactory SqlSessionFactoryBean-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="typeAliasesPackage" value="com.mysite.entity"/>
    <property name="mapperLocations">
        <list>
            <value>classpath:com.mysite.mapper/*Mapper.xml</value>
        </list>
    </property>
    </bean>
    <!--创建DAO对象 MapperScannerConfigure-->
    <bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
    <property name="basePackage" value="com.mysite.dao"/>
    </bean>

Spring与MyBatis整合细节

  • 问题:Spring与MyBatis整合后,为什么Dao不提交事务,但是数据能够插入到数据库中?
    Connection --> 事务

本质上控制连接对象(Connection) ---> 连接池(DataSource)

MyBatis提供的连接池对象 ---> 创建Connection
Connection.setAutoCommit(false) 手工控制事务
Druid(c3p0,DBCP)作为连接池 ---> 创建Connection
Connection.setAutoCommit(true) 自动控制事务

因为Spring与MyBatis整合时,引入了外部连接池对象,保持自动的事务提交这个机制(Connection.setAutoCommit(true))

三、Spring的事务处理

控制事务的底层 都是Connection对象完成的

Spring控制事务,通过AOP方式进行事务

原始对象

public void XxxUserServiceImpl(){
    1. 原始对象 -> 原始方法 -> 核心功能 (业务处理+DAO调用)
    2. DAO作为service的成员变量,依赖注入的方式进行赋值
}

额外功能

1.org.springframework.jdbc.datasource.DataSourceTransactionManager
2.注入DataSource

//方式1. MethodInterceptor
public Object invoke(MethodInvocation invocation){
    try{
        Connection.setAutoCommit(false);
        Object ret = invocation.proceed();
        Connection.commit();
    }catch(Exception e){
        Connection.rollback();
        throw new RuntimeException();
    }

    return ret;
}
//方式2. @Aspect @Around

切入点

@Transactional
事务的额外功能加入给哪些业务方法
1. 类上:类中所有的方法都会加入事务
2. 方法上:这个方法会加入事务

Spring控制事务的编码

  • 搭建开发环境(jar)
    <!--Spring整合事务-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.3.22</version>
    </dependency>
  • 编码
    <!--1. 原始对象-->
    <bean id="userService" class="com.mysite.service.UserServiceImpl">
    <property name="userDao" ref="userDao"/>    <!--Spring整合MyBatis后,ref=userDao直接从SqlSessionFactory中创建的DAO对象中取-->
    </bean>
    <!--2. 额外功能
    开启事务-->
    <!--通过 DataSourceTransactionManager 类获取dataSource连接池,从连接池中获取Connection连接对象,完成额外功能-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--3. 切入点-->
    @Transactional  /*3. 切入点*/
    public class UserServiceImpl implements UserService{
    private UserDao userDao;
    }
    <!--4. 组装切入点和额外功能
    自动扫描 切入点@Transactional-->
    <!--引入的 annotation-driven 结尾是tx的-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
  • 细节
    <tx:annotation-driven transaction-manager="dataSourceTransactionalManager" proxy-target-class="true"/>
    进行动态代理底层实现的切换
    默认 false  JDK创建动态里
        true    Cglib

    四、基于标签的事务配置方式

    基于注解 @Transactional 的事务配置回顾
    <!--1. 原始对象-->
    <bean id="userService" class="com.mysite.service.UserServiceImpl">
    <property name="userDao" ref="userDao"/>    <!--Spring整合MyBatis后,ref=userDao直接从SqlSessionFactory中创建的DAO对象中取-->
    </bean>
    <!--2. 额外功能
    开启事务-->
    <!--通过 DataSourceTransactionManager 类获取dataSource连接池,从连接池中获取Connection连接对象,完成额外功能-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--3. 切入点-->
    @Transactional  /*3. 切入点*/
    public class UserServiceImpl implements UserService{
    private UserDao userDao;
    }
    <!--4. 组装切入点和额外功能
    自动扫描 切入点@Transactional-->
    <!--引入的 annotation-driven 结尾是tx的-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
  • 基于标签的事务配置
    <!--1. 原始对象-->
    <bean id="userService" class="com.mysite.service.UserServiceImpl">
    <property name="userDao" ref="userDao"/>    <!--Spring整合MyBatis后,ref=userDao直接从SqlSessionFactory中创建的DAO对象中取-->
    </bean>
    <!--2. 额外功能
    事务配置-->
    <!--通过 DataSourceTransactionManager 类获取dataSource连接池,从连接池中获取Connection连接对象,完成额外功能-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--3. 事务属性-->
    <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
    <tx:attributes>
        <tx:method name="register" isolation="DEFAULT",propagation="SUPPORTS"></tx:method>
        <tx:method name="login" ...></tx:method>
        等效于
        @Transactional(isolation=,propagation=)
            public void register(){
        }
    </tx:attributes>
    </tx:advice>
    <!--4.通过AOP编程,组装 3和切面-->
    <aop:config>
    <aop:pointcut id="pc" expression="execution(* com.mysite.service.UserServiceImpl.register(..))"></aop:pointcut>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"></aop:advisor>
    </aop:config>

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注