【Spring 事務管理系列之一】Spring使用JDBC的事務管理例子

    本打算系列之一把此次寫的大綱列出來呢,無奈本身沒想好,只有大體定一個方向,待後面補充,或者從新組織這一系列。
java

作幾個概念的澄清和一些基礎東西的介紹node

一、假設你熟悉JDBC提供的api操做,好比:mysql

    JDBC提供的事務處理API很是少,請不要被Spring中事務處理的那一堆源代碼所打擊得信心盡失,這些框架提供的事務處理功能歸根結底主要經過以Connection類的方法完成:spring

Connection.setAutoCommit(boolean);
Connection.commit();
Connection.rollback();

二、本地事務和分佈式事務sql

    本地(Local Transaction)事務指只有一個數據源參與的事務,好比只有數據庫或者只有JMS;分佈式事務(Distributed Transaction)指有多個數據源同時參與的事務,好比一項操做須要同時訪問數據庫和經過JMS發送消息,或者一項操做須要同時訪問兩個不一樣數據庫。對於分佈式事務,Java提供了JTA規範,它的原理與本地事務存在不一樣。 鑑於多數狀況下Java事務爲本地事務。數據庫

三、線程安全的基礎api

    爲何會扯到線程安全呢,由於一次DB的鏈接是Connection對象決定的,同一個Connection對象,有可能會同事被多個Thread訪問,同時瞭解ThreadLocal【1】來解決多線程之間的共享問題。
安全

四、Spring 事務管理系列之一(JDBC的事務管理例子)多線程

    這個是開篇,經過這個系列一,會直觀的展現一下事務,給剛接觸的同窗一點直觀的感知,固然可能有本身理解不當的地方,也請大牛指出。框架

    本文將使用兩張表來演示事務的處理過程,怎麼來證實事務在執行了呢?通常狀況下是save以後數據庫db能看獲得,可是這不能證實事務起做用了,這個例子中會經過使用插入一張customer表,一張Address表,在插入customer表以後,拋出異常,在插入address表,這兩個操做是放在一個事務裏面的,若是最後表裏面沒有數據,則代表,事務確實起做用啦,要麼全插,要麼不插。

    4.一、建立database

customer.sql

CREATE TABLE `Customer` (
  `id` int(11) unsigned NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

address.sql

CREATE TABLE `Address` (
  `id` int(11) unsigned NOT NULL,
  `address` varchar(20) DEFAULT NULL,
  `country` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

數據庫表結構:

  

4.二、項目使用maven進行管理,因爲本項目使用jdbc鏈接mysql,因此包含mysql-connector-java,spring-tx,由於要實用JDBCTemplate因此又包括spring-jdbc其餘依賴以下:

<properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>3.0.6.RELEASE</spring-framework.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

		<!-- Test -->
		<junit.version>4.11</junit.version>

	</properties>

	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
                <dependency>
                  <groupId>cglib</groupId>
                  <artifactId>cglib-nodep</artifactId>
                  <version>3.1</version>
                </dependency>
		<!-- Spring JDBC and MySQL Driver -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.0.5</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- Test Artifacts -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring-framework.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

	</dependencies>

4.三、具體實現

    關於spring.xml bean的配置,還有pojo的配置很少作介紹。主要提出來事務處理的邏輯:

public void create(Customer customer) {
		String queryCustomer = "insert into Customer (id, name) values (?,?)";
		String queryAddress = "insert into Address (id, address,country) values (?,?,?)";

		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

		jdbcTemplate.update(queryCustomer, new Object[] { customer.getId(),
				customer.getName() });
		System.out.println("Inserted into Customer Table Successfully");
		jdbcTemplate.update(queryAddress, new Object[] { customer.getId(),
				customer.getAddress().getAddress(),
				customer.getAddress().getCountry() });
		System.out.println("Inserted into Address Table Successfully");
	}

可見,customer表插入以後,打印「Inserted into Customer Table Successfully」而後再插入Address那張表,咱們在設計Address這張表的時候要求Address的地址字段是小於20 chars的長度,咱們在測試代碼裏面故意構造,大於20的長度,讓其拋出異常,代碼以下:

Customer customer = new Customer();
		customer.setId(2);
		customer.setName("lianzi");
		Address address = new Address();
		address.setId(2);
		address.setCountry("china");
		// setting value more than 20 chars, so that SQLException occurs
		address.setAddress("********************************************");
		customer.setAddress(address);
		return customer;

運行結果:

同時查看,數據庫發現customer表中,並沒有數據,符合預期,代表事務生效啦。

五、問題和思考?

spring是如何實現事務管理的呢?下面幾篇文章,會實現一個很簡單的相似spring事務管理的功能。

代碼下載

相關文章
相關標籤/搜索