程序员的知识教程库

网站首页 > 教程分享 正文

快速搞定Spring JDBC和事务管理(spring事务管理 详解)

henian88 2024-10-14 10:04:02 教程分享 11 ℃ 0 评论

学习目标

1、数据源配置

2、jdbcTemplate使用

3、jdbcDaoSupport使用

4、Spring事务

学习内容

1、数据源配置

DBCP数据源

Spring在第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP,其二是 C3P0。可以在Spring配置文件中利用这两者中任何一个配置数据源。

参考:

 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
 destroy-method="close"> 
 <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
 <property name="url" value="jdbc:mysql://localhost:3309/sampledb" /> 
 <property name="username" value="root" /> 
 <property name="password" value="1234" /> 
 </bean>

BasicDataSource提供了close()方法关闭数据源,所以必须设定destroy-method=”close”属性, 以便Spring容器关闭时,数据源能够正常关闭。除以上必须的数据源属性外,还有一些常用的属性:

defaultAutoCommit:设置从数据源中返回的连接是否采用自动提交机制,默认值为 true;

defaultReadOnly:设置数据源是否仅能执行只读操作, 默认值为 false;

maxActive:最大连接数据库连接数,设置为0时,表示没有限制;

maxIdle:最大等待连接中的数量,设置为0时,表示没有限制;

maxWait:最大等待秒数,单位为毫秒, 超过时间会报出错误信息;

validationQuery:用于验证连接是否成功的查询SQL语句,SQL语句必须至少要返回一行数据, 如你可以简单地设置为:“select count(*) from user”;

removeAbandoned:是否自我中断,默认是 false ;

removeAbandonedTimeout:几秒后数据连接会自动断开,在removeAbandoned为true,提供该值;

logAbandoned:是否记录中断事件, 默认为 false;

C3P0数据源

C3P0是一个开放源代码的JDBC数据源实现项目,它在lib目录中与Hibernate一起发布,实现了JDBC3和JDBC2扩展规范说明的 Connection 和Statement 池。

 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
 destroy-method="close"> 
 <property name="driverClass" value=" oracle.jdbc.driver.OracleDriver "/> 
 <property name="jdbcUrl" value=" jdbc:oracle:thin:@localhost:1521:ora9i "/> 
 <property name="user" value="admin"/> 
 <property name="password" value="1234"/> 
 </bean>

ComboPooledDataSource和BasicDataSource一样提供了一个用于关闭数据源的close()方法,这样我们就可以保证Spring容器关闭时数据源能够成功释放。

C3P0拥有比DBCP更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制:

acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目;

acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30;

acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000;

autoCommitOnClose:连接关闭时默认将所有未提交的操作回滚。默认为false;

automaticTestTable: C3P0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数,那么属性preferredTestQuery将被忽略。你 不能在这张Test表上进行任何操作,它将中为C3P0测试所用,默认为null;

breakAfterAcquireFailure:获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调 用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false;

checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒,默认为0;

connectionTesterClassName: 通过实现ConnectionTester或QueryConnectionTester的类来测试连接,类名需设置为全限定名。默认为 com.mchange.v2.C3P0.impl.DefaultConnectionTester;

idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;

initialPoolSize:初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3;

maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0;

maxPoolSize:连接池中保留的最大连接数。默认为15;

maxStatements:JDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属 于单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatements与 maxStatementsPerConnection均为0,则缓存被关闭。默认为0;

maxStatementsPerConnection:连接池内单个连接所拥有的最大缓存Statement数。默认为0;

numHelperThreads:C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3;

preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认为null;

propertyCycle: 用户修改系统配置参数执行前最多等待的秒数。默认为300;

testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都 将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable

等方法来提升连接测试的性能。默认为false;

testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false

JNDI数据源

如果应用配置在高性能的应用服务器(如WebLogic或Websphere等)上,我们可能更希望使用应用服务器本身提供的数据源。应用服务器的数据源 使用JNDI开放调用者使用,Spring为此专门提供引用JNDI资源的JndiObjectFactoryBean类。

 <bean id="TerasolunaSampleDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
 <property name="jndiName">
 <value>java:comp/env/jdbc/test1</value>
 </property>
 </bean>

tomcat下的:context.xml文件参考:

或者放在项目中的META-INF目录下:

 <Context>
 <Resource name="jdbc/test1" 
 auth="Container"
 type="org.apache.commons.dbcp.BasicDataSource" 
 username="root"
 password="123456" 
 driverClassName="com.mysql.jdbc.Driver"
 url="jdbc:mysql://localhost:3306/test1"
 initialSize="10" 
 maxActive="100"
 maxIdle="10" 
 minIdle="5"
 maxWait="10000" 
 factory="org.apache.naming.factory.BeanFactory"/>
 </Context>

Druid数据源

Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。

Druid可以做什么?

  • 替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
  • 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
  • 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
  • SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
  • 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。

使用:

1、引入jar包

 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-jdbc</artifactId>
 <version>${spring.version}</version>
 </dependency>
 <dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>druid</artifactId>
 <version>1.1.16</version>
 </dependency>

2、配置数据源

 <!--加载资源文件-->
 <context:property-placeholder location="classpath:jdbc.properties"/>
 <!--配置数据源-->
 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
 <property name="driverClassName" value="${driver}"/>
 <property name="url" value="${url}"/>
 <property name="username" value="root"/>
 <property name="password" value="123456"/>
 <!-- 配置初始化大小、最小、最大 -->
 <property name="initialSize" value="5" />
 <property name="minIdle" value="10" />
 <property name="maxActive" value="20" />
 <!-- 配置获取连接等待超时的时间 -->
 <property name="maxWait" value="60000" />
 <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
 <property name="timeBetweenEvictionRunsMillis" value="2000" />
 <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
 <property name="minEvictableIdleTimeMillis" value="600000" />
 <property name="maxEvictableIdleTimeMillis" value="900000" />
 <property name="validationQuery" value="select 1" />
 <property name="testWhileIdle" value="true" />
 <property name="testOnBorrow" value="false" />
 <property name="testOnReturn" value="false" />
 <property name="keepAlive" value="true" />
 <property name="phyMaxUseCount" value="100000" />
 <!-- 配置监控统计拦截的filters -->
 <property name="filters" value="stat" />
 </bean>

配置参考

2、Spring JDBC

简述:

Spring的JDBC框架将数据访问的过程中获取连接、释放资源、异常处理、遍历查询结果等必须的样板代码封装隐藏到模板类之下,从而简化我们的JDBC 代码.

Spring针对JDBC提供了2个模板类:

  • JdbcTemplate:Spring 里最基本的 JDBC 模板,利用 JDBC 和简单的索引参数查询提供对数据库的简单访问。
  • NamedParameterJdbcTemplate:能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数,这有利于简化动态组合条件查询的实现,也不容易搞混参数。

JdbcTemplate模板使用:

示例:

配置JdbcTemplate

 <!--配置JdbcTemplate-->
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
 <!--关联数据源-->
 <property name="dataSource" ref="dataSource"/>
 </bean>

使用:

 @Repository
 public class DeptDaoImpl implements DeptDao {
 ?
 @Autowired //自动注入 JdbcTemplate
 private JdbcTemplate jdbcTemplate; //支持参数化的sql命令
 ?
 @Override
 public int add(Dept dept) {
 return jdbcTemplate.update("insert into dept(dname) values(?)",dept.getDname());
 }
 @Override
 public List<Dept> queryAll() {
 //行数据和实体的映射
 RowMapper<Dept> mapper=new BeanPropertyRowMapper<>(Dept.class);
 return jdbcTemplate.query("select * from dept", mapper);
 }
 ?
 @Override
 public Dept query(Integer id) {
 RowMapper<Dept> mapper=new BeanPropertyRowMapper<>(Dept.class);
 return jdbcTemplate.queryForObject("select * from dept where deptno=?", new Object[]{id},mapper);
 }
 }

NamedParameterJDBCTemplate使用

配置:

 <bean id="jdbcTemplate2" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
 <constructor-arg index="0" ref="dataSource"/>
 </bean>
 @Autowired
 private NamedParameterJdbcTemplate template;
 
 @Override
 public int add(Dept dept) {
 Map<String,Object> map=new HashMap<>();
 map.put("dname", dept.getDname());
 //命名化的参数 ,可以不按照顺序传递
 return template.update("insert into dept(dname) values(:dname)", map);
 }

spring对jdbc dao的支持:

使用JdbcDaoSupport类

 public class DeptDaoImpl2 extends JdbcDaoSupport implements DeptDao {
 @Override
 public int add(Dept dept) {
 return this.getJdbcTemplate().update("insert into dept(dname) values(?)",dept.getDname());
 }
 }
 <bean id="deptDao2" class="com.aaa.dao.DeptDaoImpl2">
 <property name="jdbcTemplate" ref="jdbcTemplate" />
 </bean>

使用NamedParameterJdbcDaoSupport类

(略)

3、spring事务

事务定义:

一系列的数据操作作为整体执行,要么都执行,要么都 回滚。机制

事务特点:(ACID)

  • 原子性(Atomicity)

  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。

  • 一致性(Consistency)

  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。 

  • 隔离性(Isolation)

  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。  

  • 持久性(Durability)

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的。

事务的不同的隔离级别可能会导致的问题:

脏读:

  脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

不可重复读

  不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

  例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。

  不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

虚读(幻读)

  幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

事务的隔离级别:

  • default:后台数据库默认的隔离级别(spring中设置)
  • read_uncommited:未提交读;允许读取还未提交了的改变的数据。可能导致,脏、幻、和重复读。
  • read_committed:已提交读,数据库中的默认的隔离 级别;允许在提交事务后读取数据。防止脏读。还可能会导致幻和重复读。
  • repeatable_read:重复读;对相同数据的读取是一致的,除非数据被事务本身改变。可防止脏读 和不可重复读,但幻读仍可发生。
  • serializable:串行化;可防止各种脏、幻和重复读。效率最低。

事务的传播机制:

  • propagation_required:如果当前没有事务,就新建一个事务;如果已经存在一个事务中,加入到这个事务中。(A方法中调用B方法 )
  • propagation_supports:支持当前事务,如果当前没有事务,就以非事务的方式运行。
  • propagation_mandatory:强制使用当前事务,如果没有事务就会抛出异常。
  • propagation_requires_new:新建事务,如果当前已经存在事务,就挂起事务。
  • propagation_not_supported:以非事务方式运行,如果当前存在事务,就把事务挂起。
  • propagation_never:以非事务方式运行,如果当前存在事务,就抛出异常。
  • propagation_nested:如果当前存在事务,就在事务 内部嵌套执行。如果当前没有事务则执行与require相同的行为。

spring事务管理:

1、编程式事务(很少用)

 <!--事务管理器类-->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource"/>
 </bean>
 ?
 <!--编程式事务的模板类-->
 <bean id="trans" class="org.springframework.transaction.support.TransactionTemplate">
 <property name="transactionManager" ref="transactionManager"></property>
 </bean>

2、声明式事务(常用)

实现原理:基于aop实现

2.1 以xml的方式配置

 <tx:advice id="tx" transaction-manager="transactionManager">
 <tx:attributes>
 <!--propagation:事务的传播行为
 isolation:DEFAULT隔离级别
 read-only="true":只读
 timeout:超时时间
 -->
 <tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT" read-only="true" timeout="-1"/>
 <tx:method name="update*" propagation="REQUIRED"/>
 </tx:attributes>
 </tx:advice>
 ?
 <aop:config>
 <aop:pointcut id="p1" expression="execution(* com.aaa.service..*.*(..))"/>
 <aop:advisor advice-ref="tx" pointcut-ref="p1"/>
 </aop:config>
 

2.2 以注解的方式配置(常用)

 ?
 <!--事务管理器类-->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <!--引入数据源-->
 <property name="dataSource" ref="dataSource"/>
 </bean>
 <!--开启注解式事务-->
 <tx:annotation-driven transaction-manager="transactionManager"/>
 ?

使用:

在业务层的方法中增加@Transactional注解

 @Transactional (propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
 @Override
 public int add(Dept dept) {
 //一旦发生异常,回滚
 //add1()
 //异常
 //add2()
 return deptDao.add(dept);
 }

总结

1、spring jdbc中(数据源配置,模板类使用,dao类使用)

2、spring如何管理事务。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表