Spring整合Mybatis


1. 导入依赖


  1. 第一步新建Maven项目
  2. 在pom.xml的<dependencies></dependenies>导入依赖
  3. spring核心、mybatis核心、mybatis-spring整合包、log4j日志、common-mysql-java驱动、Druid数据库连接池、spring-orm整合包、Junit测试,具体看这里:Spring框架用到依赖

2. 新建applicationContext.xml文件


2.1 jdbc.properties

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3308/companydb?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
jdbc.init=1
jdbc.minIdle=1
jdbc.maxActive=20

2.2 配置连接池、SqlSessionFactory

配置DataSource、SqlSessionFactory

<?xml version="1.0" encoding="utf8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/p
                           http://www.springframework.org/schema/p/spring-p.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd "
>
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="${jdbc.init}"/>
        <property name="maxWait" value="60000"/>
        <property name="timeBetweenEvictionRunsMillis" value="50000"/>
        <property name="minEvictableIdleTimeMillis" value="3000"/>
    </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--        注入连接池-->
        <property name="dataSource" ref="dataSource"></property>
        <!--注入dao-mapper文件信息,如果映射文件和dao接口 同包同名 则此配置可省略-->
<!--        类似与mapper文件在Mybatis-config.xml文件中的注册-->
        <property name="mapperLocations">
            <list>
                <value>classpath:com/lyx/dao/*.xml</value>
            </list>
        </property>
        <!--        为dao-mapper文件中的实体定义缺省包路径
        如:<select id="queryAll" resultType="User">中User类可以不定义包-->
<!--        类似与在Mybatis-config.xml文件中的typeAliases-->
        <property name="typeAliasesPackage" value="com.lyx.entity"></property>
    </bean>

</beans>

2.3 写个UserDao-Mapper.xml映射文件


  • 注意文件头,与Mybatis-config.xml文件头不一致
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lyx.dao.UserDao">
    <resultMap id="user_resultMap" type="User">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="gender" property="gender"></result>
        <result column="regist_time" property="registTime"></result>
    </resultMap>

    <select id="queryUsers" resultMap="user_resultMap">
        select id,username,password,gender,regist_time
        from t_user
    </select>
</mapper>

2.4 写个测试类

public class TestSpringMybatis {
    @Test
    public void test(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
        SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)context.getBean("sqlSessionFactory");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> users = mapper.queryUsers();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

运行报错:在这里插入图片描述

解决办法:Error java 错误 不支持发行版本5
运行报错:.xml文件在编译时不能被编译到测试文件中,所以运行过程中找不到我注册的.xml文件,从而导致我上面再UserDao-Mapper.xml文件中定义的<mapper namespace=“com.lyx.dao.UserDao”/>没有注册
在这里插入图片描述
mybatis的xml文件无法被maven加载到target文件中的问题

	<build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

运行成功
在这里插入图片描述

2.5 配置MapperScannerConfigurer

理解:帮助我们把Mybatis的Dao实现放到工厂中,我们知道,用来mybatis之后,我们是不写UserDaoImpl这种实现类的,我们要想办法把这个实现类对象放到工厂中


作用:管理Dao实现类的创建,并创建Dao对象,存入工厂管理

  1. 扫描所以DAO接口,去构建DAO实现
  2. 将DAO实现存入工厂管理
  3. DAO实现对象在工厂中的id是:“首字母小写的-接口的类名”,例如UserDao==>userDAO,OrderDAO==>orderDAO
    <bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--        dao接口所在的包 如果有多个包,可以用逗号或者分号分隔
 <property name="basePackage" value="com.lyx.dao,com.xmq.dao"></property>
 <property name="basePackage" value="com.lyx.dao;com.xmq.dao"></property>
 -->
        <property name="basePackage" value="com.lyx.dao"></property>
<!--        如果工厂中只有一个SqlSessionFactory的bean,此配置可省略-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
      </bean>

2.6 配置Service


在这里插入图片描述
在这里插入图片描述

    <bean id="userService" class="com.lyx.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
  • 注意ref中的值是对应DAO接口的首字母小写的接口名

2.7 测试一下

在这里插入图片描述

@Test
    public void test2(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
        UserService userService = (UserService)context.getBean("userService");
        List<User> users = userService.queryUsers();
        for (User user : users) {
            System.out.println(user);
        }
    }

3. 事务【重点】


3.1 配置DataSourceTransactionManager


  • 事务管理器,其中ref=dataSource,可以控制事务功能(commit,rollback等)就是对访问或者操作dataSource里面配置的数据库时,进行事务控制
  • 注意DataSourceTransactionManager和SqlSessionFactoryBean要注入同一个DataSource的Bean,否则事务控制失败!

在这里插入图片描述

代码如下:

<!--    引入一个事务管理,其中依赖DataSource,借以获得连接,进而控制事务逻辑-->
    <bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

3.2 配置事务通知


在这里插入图片描述

  • 基于刚刚的事务管理器,我们为其配置一个事务通知,生成一个额外功能,advice,此advice可以切入任何需要事务的方法,通过事务管理器为方法控制事务
  • 代码如下
    <!--引入一个事务管理,其中依赖DataSource,借以获得连接,进而控制事务逻辑-->
    <bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <tx:advice id="txManager" transaction-manager="tx">
        <tx:attributes>
            <tx:method name="queryUsers" read-only="false" isolation="DEFAULT" rollback-for="Exception"/>
            <tx:method name="query*" propagation="SUPPORTS" timeout="-1" no-rollback-for="Exception"/>
        </tx:attributes>
    </tx:advice>

  • name里面的query*,意思是所有以query开头的方法,切入事务控制

3.3 事务属性


在这里插入图片描述

  • 上面的事务属性的几个标识,依次为只读,事务隔离级别,需要回滚的异常类,事务传播属性,超时(一般不用),不需要回滚的异常类
  • 下面挑几个侧重讲解

3.3.1 隔离级别

isolation


isolation的值有5种:

  • default 默认值
  • read-uncommitted 读未提交
  • read-committed 读提交
  • repeatable-read 可重复读
  • serializable 序列化读

以上5种值的隔离级别依次升高!

事务isolation这个属性的作用是什么?事务并发时的安全问题:

  1. 丢失更新(lost update):在完全未隔离事务的情况下,两个事物更新同一条数据资源,如果其中一个事务异常终止,回滚造成第一个完成的更新也同时丢失。
  2. 脏读(dirty read):一个事务查询到另一个事务还未提交的更新数据,read-commited读提交可防止
  3. 幻影读(phantom read):一个事务多次读取,每一次读取结果都不一样,由于是另一个事务在这期间做了插入或者删除了数据造成的。serializable可防止
  4. 不可重复读(unrepeated read):一个事务两次读取同一行数据,结果得到不同状态结果,如中间正好另一个事务更新了该数据,两次结果相异,不可信任。repeatable-read 可重复读可防止
  5. 丢失更新2(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失。

以上5个值,我们默认使用default,当我们是Mysql数据库,spring默认使用可重复读repeatable-read,当我们是Oracle数据库,spring默认使用读提交read-commited,这两个也是安全性比较高的
如果我们不写isolation属性,默认也是default

3.3.2 传播行为

propagation


  1. 当事务涉及到事务嵌套,Service调用Service时,可以会存在问题
    两个Service层的每个方法都要自己的事务,当Service1中的方法调用了Service2中的方法,就会导致事务的嵌套,如果Service2中的方法发生了错误,该方法事务回滚,但是对调用它的Service1中的方法却没有进行回滚
  2. 传播行为可以为我们解决
  3. 有两个值,SUPPORTS,REQUIRED
  4. SUPPORTS:当不存在外部事务,则该方法也不开启事务,存在外部事务,则合并到外部事务中,比如我们的查询,不对数据库操作,只是查找的话,基本上不会开启事务,所以SUPPORTS适合查询方法使用
  5. REQUIRED:当不存在外部事务,则开启新事务,存在外部事务,则合并到外部事务中,比如我们的增删改,对数据库进行操作,肯定要存在事务控制,所以REQUIRED 适合增删改

3.3.3 timeout事务超时

当事务所需要存在的涉及被其他事务占用,则等待
-1 就是数据库指定等待时间
自定义也可以时间,用到不多

3.3.4 readonly

  1. true 只读,可提供查询效率 ,适合查询
  2. false 可读可写,适合增删改

3.3.5 事务回滚rollback-for

  1. 如果事务中抛出,RuntimeException,则自动回滚
  2. 但是如果事务中抛出,CheckException(非运行时异常 Exception),不会自动回滚,而是默认提交事务
  3. 怎么解决不会自动回滚的异常呢?处理方案:将CheckException转换成RuntimeException上抛,或者 设置 rollback -for=“exception”

3.4 事务编织

将刚刚的事务的Advice的id切入需要事务的业务方法中,这就是Spring的AOP
在这里插入图片描述

    <bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <tx:advice id="txManager" transaction-manager="tx">
        <tx:attributes>
            <tx:method name="queryUsers" read-only="false" isolation="DEFAULT" rollback-for="Exception"/>
            <tx:method name="query*" propagation="SUPPORTS" timeout="-1" no-rollback-for="Exception"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="pc" expression="execution(* com.lyx.service.UserServiceImpl.*queryUsers())"/>
        <aop:advisor advice-ref="txManager" pointcut-ref="pc"/>
    </aop:config>

4. 注解使用

@Transactional
工厂配置的<tx:advice…和<aop:config…可以省略

@Transactional(isolation=Isolation.READ_COMITTED,propagation=Propagation.REQUIRED,readOnly=false,rollback-for=Exception.class,timeout=-1)
public class UserServiceImpl implements UserService{
	
	//该方法直接的事务控制,仅对此方法有效
	@Transactional(propagation=Propagation.SUPPORTS)
	public List<User> queryAll(){
		return userDao.queryAll();
	}
	//该方法直接的事务控制,仅对此方法有效
	@Transactional(propagation=Propagation.REQUIRED)
	public void save(User user){
		userDao.save(user);
	}
}

要想要注解能够执行,还需要配置如下

  1. 添加注解:@ComponentScan 告知spring,哪些包中,有被注解的类、方法、属性,作用和Spring的xml配置文件中的<context:component-scan base-package=“com.lyx”/>一样
  2. <tx:annotation-driven transaction-manager=“txManager”/>

5. applicationContext.xml文件所有内容

<?xml version="1.0" encoding="utf8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/p
                           http://www.springframework.org/schema/p/spring-p.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd "
>
    <bean id="userService" class="com.lyx.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
    
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="${jdbc.init}"/>
        <property name="maxWait" value="60000"/>
        <property name="timeBetweenEvictionRunsMillis" value="50000"/>
        <property name="minEvictableIdleTimeMillis" value="3000"/>
    </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--注入连接池-->
        <property name="dataSource" ref="dataSource"></property>
        <!--注入dao-mapper文件信息,如果映射文件和dao接口 同包同名 则此配置可省略-->
		<!--类似与mapper文件在Mybatis-config.xml文件中的注册-->
        <property name="mapperLocations">
            <list>
                <value>classpath:com/lyx/dao/*.xml</value>
            </list>
        </property>
        <!--为dao-mapper文件中的实体定义缺省包路径
        如:<select id="queryAll" resultType="User">中User类可以不定义包-->
		<!--类似与在Mybatis-config.xml文件中的typeAliases-->
        <property name="typeAliasesPackage" value="com.lyx.entity"></property>
    </bean>
    
    <bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!--dao接口所在的包 如果有多个包,可以用逗号或者分号分隔
		 <property name="basePackage" value="com.lyx.dao,com.xmq.dao">		</property>
		 <property name="basePackage" value="com.lyx.dao;com.xmq.dao"></property>
		 -->
        <property name="basePackage" value="com.lyx.dao"></property>
		<!-- 如果工厂中只有一个SqlSessionFactory的bean,此配置可省略-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
   </bean>
      
    <!--引入一个事务管理,其中依赖DataSource,借以获得连接,进而控制事务逻辑-->
    <bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

	<!--事务通知-->
    <tx:advice id="txManager" transaction-manager="tx">
    	<!--事务属性-->
        <tx:attributes>
            <tx:method name="queryUsers" read-only="false" isolation="DEFAULT" rollback-for="Exception"/>
            <!--query*:以query开头的所有方法,切入此方法,采用对应事务实行-->
            <tx:method name="query*" propagation="SUPPORTS" timeout="-1" no-rollback-for="Exception"/>
        </tx:attributes>
    </tx:advice>

	<!--编织:声明事务控制-->
    <aop:config>
        <aop:pointcut id="pc" expression="execution(* com.lyx.service.UserServiceImpl.*queryUsers())"/>
        <aop:advisor advice-ref="txManager" pointcut-ref="pc"/>
    </aop:config>
    
    <context:component-scan base-package="com.lyx"/>
	<tx:annotation-driven transaction-manager="txManager"/>
</beans>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

素心如月桠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值