Spring事务+JDBC小结

数据库事务

原子性: 多个操作组成最小不可分割单元。
一致性: 操作成功后,数据库的状态和业务规则是一致的。
隔离性: 并发数据处理时,相互不干扰。
持久性: 一旦事物提交成功后,数据的操作被记入库中。

数据库并发问题

脏读:读取不可靠的数据(数据被回滚了),Oracle不会发生脏读情况。
不可重复读:同一事务中两次读取数据有差异(数据被别的事务修改、删除)。
幻象读:A事务读到B事务提交的新数据,导致A前后读取不一致。(很像不可重复读,不同的是幻象第二次数据是增加。采用锁表防止增加。)
第一次丢失更新:A事务撤销时,在A事务开始和结束的B事务也抹杀了。无视B的存在。
第二次丢失更新:A事务覆盖B事务已提交的数据,造成B事务操作丢失。

事务隔离级别

事务隔离级别
隔离级别   脏    读不可重复读   幻象读第一类丢失更新第二类丢失更新
READ UNCOMMITED允许允许允许不允许允许
READ COMMITTED不允许允许允许不允许允许
REPEATABLE READ不允许不允许允许不允许不允许
SERIALIZABLE不允许不允许不允许不允许不允许

JDBC+事务

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

//JDBC的事务
public class JDBC_Demo {
	public static void main(String[]args) throws SQLException {
		Connection conn = null;
		try {
			//获取数据连接...
			conn = DriverManager.getConnection("");
			//关闭自动提交事务
			conn.setAutoCommit(false);
            //设置事务隔离级别
			conn.setTransactionIsolation(Connection.TRANSACTION_NONE);
			
			Statement stmt = conn.createStatement();
			int rows = stmt.executeUpdate("insert into user u values(1,'大黑')");
            
			//提交事务
			conn.commit();
		} catch (Exception e) {
			// 回滚事务
			conn.rollback();
		}finally {
			//......
		}
	}
}

Spring+事务

Spring用到了ThreadLocal和单例来保证线程安全

数据源配置

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
         http://www.springframework.org/schema/util
         http://www.springframework.org/schema/util/spring-util-4.1.xsd">
         
    <!-- DBCP数据源 -->
    <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:3306/db_database17"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!-- C3P0数据源 -->
    <bean id="mySource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"
          p:driverClass="oracle.jdbc.driver.OracleDriver"
          p:jdbcUrl="jdbc:oracle:thin:@localhost:1521:ora9i"
          p:use="admin"
          p:password="123456" />    
</beans>

Spring事务管理器实现类 => DataSourceTransactionManager

DataSourceTransactionManager:可管理JDBC和MyBatis的事务


<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
         http://www.springframework.org/schema/util
         http://www.springframework.org/schema/util/spring-util-4.1.xsd">
    
    <!-- DBCP数据源 -->
    <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:3306/db_database17"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!-- 引用DBCP数据源,基于DBCP数据源管理事务。 -->
    <bean id="transactionManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
      p:dataSource-ref="dataSource"/>   
</beans>

事务同步管理器

Spring将JDBC的Connection、Hibernate的Session等访问数据库的链接、会话对象称为资源,这些资源同一时刻不线程共享。Spring用ThreadLocal为每个线程做了独立的副本,同时维护事务配置的属性和运行状态信息。事务同步管理器是Spring事务管理的基石。

事务传播行为

说白了就是类与类间的调用。Spring通过事务传播行为控制当前事务如何传播到被调用的方法中。

事务传播行为类型  说  明  
PROPAGATION_REQUIRED如果没有当前事务,则新建一个事务;如果已存在一个事务,则加入这个事务中。
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,以非事务方式运行。
PROPAGATION_MANDATORY使用当前事务。当前没有事务,抛异常。
PROPAGATION_REQUIRES_NEW新建事务。如果当前存在事务,则把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式操作。如果当前存在事务,则把事务挂起。
PROPAGATION_NEVER以非事务方式执行。如果当前存在事务,则抛异常。
PROPAGATION_NESTED如果当前存在事务,则嵌套事务内运行;当前无事务,则新建事务。

使用XML声明事务

使用原始的TransactionProxyFactoryBean代理类对业务类进行代理

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class BbtForum {
	
	public interface ForumDao {}

	public interface TopicDao{}
	
	public interface PostDao{}
	
	public ForumDao forumDao;
	
	public TopicDao toipDao;
	
	public PostDao postDao;
	
	public void addTopic() {
		System.out.println("添加");
	}

	public void getForum() {
		System.out.println("查找");
	}
	
}
    <!-- DBCP数据源 -->
    <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:3306/db_database17"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
    <!-- 引用DBCP数据源,基于DBCP数据源管理事务。 -->
    <bean id="transactionManager" 
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          p:dataSource-ref="dataSource"/>
      
      <!-- 需要实施事务增强的目标Bean -->
     <bean id="bbtForumTarget" class="com.nan.BbtForum"
            p:forumDao-ref="forumDao"
            p:topicDao-ref="topicDao"
            p:postDao-ref="postDao" />
            
    <!--  使用事务代理工厂类为目标业务Bean提供事务增强 -->
    <bean id="bbtForum" 
          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
          p:transactionManager-ref="transactionManager"
          p:target-ref="bbtForumTarget">
          <!-- 事务属性配置 -->
	      <property name="transactionAttributes">
	          <props>	  
	          <!-- 只读事务  -->    
	             <prop key="get*">PROPAGATION_REQUIRED</prop>
	          </props>
	      </property>
     </bean>

基于AOP/tx命名空间配置事务

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
         http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
 
     <!-- DBCP数据源 -->
    <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:3306/db_database17"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
     <!-- 引用DBCP数据源,基于DBCP数据源管理事务。 -->
    <bean id="txManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
      p:dataSource-ref="dataSource"/>
      
    <!-- 使用切点表达式语言定义目标方法 -->
    <aop:config>
       <!-- 通过AOP定义事务增强切面 -->
        <aop:pointcut  id="serviceMethod" expression="execution(com.jun.service.Forum.*(..))"/>
       <!-- 引用事务增强 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
    </aop:config>
    
     <!-- 事务增强 -->
     <tx:advice id="txAdvice"  transaction-manager ="txManager" >
       <!-- 事务属性定义 -->
       <tx:attributes>
         <tx:method name="get*" read-only="false" />
         <tx:method name="add*" rollback-for="Exception"/>
         <tx:method name="update*"/>
       </tx:attributes>
     </tx:advice>
</beans>

 使用注解配置声明事务

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class BbtForum_Demo {
	
	@Transactional(value="topic",readOnly=true)
	public void addTopic() {
		System.out.println("添加");
	}
	
	@Transactional(value="forum")
	public void fetForum() {
		System.out.println("查询");
	}
}
<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
         http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring/context/4.1.xsd">
    <!-- 扫描包 -->
    <context:component-scan base-package="com.nan"/> 
      
    <!-- DBCP数据源 -->
    <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:3306/db_database17"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
     <!-- 引用DBCP数据源,基于DBCP数据源管理事务。 -->
     <bean id="txManager" 
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
            p:dataSource-ref="dataSource"/>
      
     <!-- 对标注@Transactional注解的Bean进行加工处理,以织入事务管理切面 -->
     <tx:annotation-driven transaction-manager="txManager"/> 
</beans>

通过AspectJ LTW引入事务切面

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
         http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring/context/4.1.xsd">
    <!-- DBCP数据源 -->
    <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:3306/db_database17"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
    <!-- 引用DBCP数据源,基于DBCP数据源管理事务。 -->
    <bean id="transactionManager" 
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          p:dataSource-ref="dataSource"/>    
    
    <!-- 扫描包 -->
    <context:component-scan base-package="com.nan"/>
    
    <tx:annotation-driven/>
</beans>

JDBC

JDBC访问数据库的过程

  1. 加载驱动,建立连接。
  2. 创建语句对象。
  3. 执行SQL语句。
  4. 处理结果集。
  5. 关闭连接。

JDBC中一些接口

  • 驱动管理接口DriverManager
  • 连接接口 Connection、DatabasemetaData
  • 语句对象接口 Statement 、PreparedStatement 、CallableStatement
  • 结果集接口 ResultSet 、ResultSetMetaData

Driver接口及驱动类加载

要使用JDBC接口,需要先将对应数据库的实现部分(驱动)加载进来。 驱动类加载方式(Oracle)装载驱动类,驱动类通过static块实现在DriverManager中的“自动注册”
Class.forName("oracle.jdbc.driver.OracleDriver");

Connection接口

Connection接口负责应用程序对数据库的连接,在加载驱动之后,使用url、username、password三个参数,创建到具体数据库的连接。Class.forName("oracle.jdbc.OracleDriver")。
根据url连接参数,找到与之匹配的Driver对象,调用其方法获取连接
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.26:1521:tarena","name","123456");

Statement接口

//Statement接口用来处理发送到数据库的SQL语句对象,通过Connection对象创建。常用三个方法:
Statement stmt=conn.createStatement();
//1.execute方法,如果执行的sql是查询语句且有结果集则返回true,如果是非查询语句或者没有结果集,返回false
boolean flag = stmt.execute(sql);
//2.执行查询语句,返回结果集
ResultSetrs = stmt.executeQuery(sql);
//3.执行DML语句,返回影响的记录数
int flag = stmt.executeUpdate(sql);

ResultSet接口

查询的结果存放在ResultSet对象的一系列行中,指针的最初位置在行首,使用next()方法用来在行间移动,getXXX()方法用来取得字段的内容。ResultSet代表DQL查询结果,其内部维护了一个读取数据的游标,默认情况在,游标在第一行数据之前,
当调用next()方法时候,游标会向下移动,并将返回结果集中是否包含数据, 如果包含数据就返回true。
结果集还提供了很好getXXX方法用于获取结果集游标指向当前行数据。

Demo

public static void main(String[] args) throws Exception{
	//注册驱动
	String driver="oracle.jdbc.OracleDriver";
	Class.forName(driver);
	//连接数据库
	String url="jdbc:oracle:thin:@196.168.201.227:2221:orcl";
	String user="name";
	String pwd="123456";
	Connection conn=DriverManager.getConnection(url, user, pwd);
	//创建Statement
	Statement st=conn.createStatement();
	//执行SQL
	String sql="select id, name from user_";
	ResultSet rs=st.executeQuery(sql);
	//处理结果
	//rs结果集中包含一个游标,游标默认在结果集的第一行之前
	//rs.next():移动结果集游标到下一行,检查是否有数据, 如果有返回true, 否则false
	while(rs.next()){
	//getXXX(列名): 返回结果集当前行中
	// 指定列名的数据.
	int id = rs.getInt("id");
	String name=rs.getString("name");
	//输出查询结果
	System.out.println(id+","+name);
	}
	//关闭连接
	conn.close();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值