`

本地事务系列之一:JDBC操作

阅读更多
本地事务即对一个数据源进行操作。大多数数据库支持事务。

先看没有事务的时候,导致的数据不一致问题。

准备数据:
-- MySQL
-- Create the database
DROP DATABASE IF EXISTS spring;
CREATE DATABASE spring

-- Drop three tables if exist
DROP TABLE IF EXISTS FRUIT;
DROP TABLE IF EXISTS FRUIT_STOCK;
DROP TABLE IF EXISTS ACCOUNT;

-- 水果表
CREATE TABLE FRUIT (
	ID INT NOT NULL,
	FRUIT_NAME VARCHAR(100) NOT NULL,
	PRICE INT,
	PRIMARY KEY (ID)
);

-- 水果存货表
CREATE TABLE FRUIT_STOCK (
	ID INT NOT NULL,
	STOCK INT NOT NULL,
	PRIMARY KEY (ID),
	CHECK (STOCK >= 0) -- analyzed but ignored by MySQL
);

-- 账户表
CREATE TABLE ACCOUNT (
	USERNAME VARCHAR(50) NOT NULL,
	BALANCE INT NOT NULL,
	PRIMARY KEY (USERNAME),
	CHECK (BALANCE >= 0)
);

-- Add initial data
INSERT INTO FRUIT(ID, FRUIT_NAME, PRICE) VALUES(1, 'Apple', 10);
INSERT INTO FRUIT_STOCK(ID, STOCK) VALUES(1, 10);
INSERT INTO ACCOUNT(USERNAME, BALANCE) VALUES('user1', 20);

DELIMITER $$  
  
-- MySQL不支持check,使用触发器来检查约束,不满足时触发异常:
CREATE TRIGGER ACCOUNT_BALANCEGT0 BEFORE UPDATE ON account    
FOR EACH ROW  
BEGIN  
    IF NEW.balance < 0 THEN -- NEW代表更新后的记录  
        CALL xxx_yyy();
        UPDATE _xxx_yyy SET X = 1; -- 引发异常
    END IF;  
END$$

DELIMITER ;


Maven依赖:
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.10</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.26</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>3.1.2.RELEASE</version>
</dependency>


接口:
public interface FruitShop {
    // fruitId - 水果ID, userName - 用户号, count - 购买数量
    boolean purchase(int fruitId, String userName, int count);
}


实现类:
public class JdbcFruitShop implements FruitShop {

	static final Logger LOGGER = LoggerFactory.getLogger(JdbcFruitShop.class);

	@Override
	public boolean purchase(int fruitId, String userName, int count) {
		Connection conn = null;

		try {
			Class.forName("com.mysql.jdbc.Driver"); // Load the driver
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/spring?characterEncoding=utf8", "spring",
					"123456"); // Get the connection

			// Query the price
			PreparedStatement ps1 = conn.prepareStatement("SELECT PRICE FROM FRUIT WHERE ID = ?");
			ps1.setInt(1, fruitId);
			ResultSet rs = ps1.executeQuery();
			int price = 0;
			if (rs.next()) {
				price = rs.getInt(1);
			}
			ps1.close();

			// Update the stock
			PreparedStatement ps2 = conn.prepareStatement("UPDATE FRUIT_STOCK SET STOCK = STOCK - ? WHERE ID = ?");
			ps2.setInt(1, count);
			ps2.setInt(2, fruitId);
			ps2.executeUpdate();
			ps2.close();

			// Update the balance
			PreparedStatement ps3 = conn
					.prepareStatement("UPDATE ACCOUNT SET BALANCE = BALANCE - ? WHERE USERNAME = ?");
			ps3.setInt(1, price * count);
			ps3.setString(2, userName);
			ps3.executeUpdate();
			ps3.close();

		} catch (SQLException e) {
			LOGGER.error("Purchase error:", e);
		} catch (ClassNotFoundException e) {
			LOGGER.error("driver Loading error:", e);
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					LOGGER.error("Connection closing error:", e);
				}
			}
		}
		return true;
	}
}


Spring配置文件:
<?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:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
  <bean id="fruitShop" class="com.john.tx.service.impl.JdbcTxFruitShop"/>
</beans>


测试:
@Resource
FruitShop fruitShop;

@Test
public void test() {
	int fruitId = 1;
	String userName = "user1";
	int count = 3;
	fruitShop.purchase(fruitId, userName, count);
}

用户user1的余额是20,买了3个单价为10的苹果,余额不够支付,报错。但是数据处于不一致状态:fruit_stock表的苹果存量由10个减为7个,而账户表的余额还是20,需要使用事务。


使用JDBC的事务操作。
public class JdbcTxFruitShop implements FruitShop {

	@Override
	public boolean purchase(int fruitId, String userName, int count) {
   		...
   		conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/spring?characterEncoding=utf8", "spring", "123456"); // Get the connection

		conn.setAutoCommit(false); // 取消自动提交
   		...
   		ps3.close();
		conn.commit(); // 提交事务
   		...
	}
}


上面的数据源是写在代码里的,每次修改都需要重新编译,可以将其放在Spring配置中:
  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf8" />
    <property name="username" value="spring" />
    <property name="password" value="123456" />
  </bean>
  
  <bean id="fruitShop" class="com.john.tx.service.impl.JdbcTxFruitShop">
    <property name="dataSource" ref="dataSource" />
  </bean>


public class JdbcTxFruitShop implements FruitShop {

	private DataSource dataSource;

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	@Override
	public boolean purchase(int fruitId, String userName, int count) {
   		...
   		conn = dataSource.getConnection();
   		...
	}
}
分享到:
评论

相关推荐

    oracle jdbc驱动 ojdbc14-10.2.0.4.0.jar工具

    Oracle JDBC驱动还支持高级特性,如游标、批处理操作、事务控制、存储过程调用、分布式事务等。在使用过程中,开发者可以根据需求选择合适的API进行操作。 需要注意的是,随着Oracle数据库版本的更新,新的JDBC驱动...

    java之JDBC详细介绍

    1. **JDBC API**: JDBC API包含了一系列的接口和类,如`java.sql.DriverManager`、`Connection`、`Statement`、`PreparedStatement`、`ResultSet`等。它们为开发者提供了与数据库交互的标准方法。 2. **JDBC的用途*...

    JDBC.pdf

    JDBC驱动程序是实现JDBC的关键组件之一,根据其工作方式不同,可以分为以下几种类型: 1. **JDBC-ODBC桥接驱动**:这是最早的JDBC驱动类型,通过ODBC(Open Database Connectivity)接口来访问数据库。由于ODBC是一...

    JDBC连接MySQL数据库的方法浅析.pdf

    【JDBC连接MySQL数据库的方法浅析】 JDBC(Java Database Connectivity)...理解和熟练使用JDBC是每个Java开发者必备的技能之一。在实际项目中,开发者应根据需求选择合适的JDBC驱动类型,并注意性能优化和安全问题。

    java_2020_0226:JDBC和MySQL

    Java是世界上最流行的编程语言之一,尤其在企业级应用开发中占据主导地位。JDBC(Java Database Connectivity)是Java平台的标准接口,它允许Java程序与各种数据库进行交互。MySQL则是一种广泛使用的开源关系型...

    JDBC编程.pdf

    - **DriverManager**: 这是JDBC API中的主要类之一,用于加载JDBC驱动程序并建立与数据库的连接。 - **Connection**: 表示与数据库之间的连接。一旦建立了连接,就可以执行SQL语句。 - **Statement**: 用于执行简单...

    8.JDBC.pdf

    - **功能**:管理各种不同的JDBC驱动,它是JDBC API的核心类之一。 - **常用方法**: - `getConnection(String url, String username, String password)`:用于建立与数据库的连接。 - `getDrivers()`:返回已注册...

    Java之JDBC

    `JDBC(day01)-day05`.txt文件可能是系列教程的笔记,分别涵盖了JDBC的基础知识、连接数据库、执行SQL、事务处理、批处理等内容,逐步深入JDBC的学习。 综上所述,Java的JDBC提供了与数据库交互的标准接口,通过理解...

    Java基础:常用的JDBC连接数据库方法大全

    在Java编程中,JDBC(Java Database Connectivity)是Java平台的标准接口,用于连接各种关系型数据库。本篇文章将深入探讨Java中常用的JDBC连接数据库的方法,...熟练掌握这些基本操作,是Java开发人员必备的技能之一。

    JAVA设计模式之事务处理.pdf

    然而,在许多实际应用场景中,应用往往只需要处理单一的数据源(通常是数据库),这时使用本地事务(例如JDBC提供的事务管理功能)就足够了。 #### 二、事务管理的重要性 事务处理的核心在于确保一系列数据库操作...

    Java事务总结.docx

    综上所述,事务处理是数据库管理中的核心机制之一,通过合理设置事务的隔离级别和传播行为,可以有效解决并发操作带来的数据不一致问题。同时,针对分布式系统的特殊需求,还需要采用适当的事务管理技术,如JTA和两...

    07CHAPTER07--JDBC数据访问接口.pdf

    ### JDBC数据访问接口详解 #### 一、JDBC概述与结构 JDBC,全称Java Database Connectivity,是Java平台上的数据库连接技术。它允许Java应用程序连接到...掌握JDBC对于任何Java开发者来说都是必不可少的技能之一。

    WebLogic事务

    配置连接池是确保应用服务器与数据库之间高效通信的关键步骤之一。下面详细介绍配置连接池的过程: **STEP1:** 数据库类型和驱动类型的选择。对于不同的数据库类型,需要选择合适的 JDBC 驱动。例如,如果是 ...

    JDBC连接Oracle数据库

    然后,在完成一系列操作后手动提交或回滚事务: ```java conn.commit(); // 或者 conn.rollback(); ``` #### 五、SQL语句执行方式 在JDBC中,有两种主要的方式执行SQL语句:使用`Statement`和`PreparedStatement`...

    jdbc驱动合集(Oracle,sql2005,mysql,db2,sybase)

    1. **Oracle**:Oracle数据库是全球最广泛使用的商业关系型数据库系统之一,由Oracle公司开发。Oracle JDBC驱动包括 Thin、OCI 和 JMS 驱动。Thin驱动是一个纯Java驱动,无需本地库,而OCI驱动需要Oracle客户端软件...

    mysql-connector-java-5.0.4.jar

    MySQL Connector/J是MySQL数据库与Java应用程序之间的桥梁,它是一个实现了Java Database Connectivity (JDBC) API的驱动程序,允许Java开发者在Java环境中访问和操作MySQL数据库。`mysql-connector-java-5.0.4.jar`...

    Java数据库连接(初级)

    总之,学习Java数据库连接(JDBC)是成为一名合格的Java开发者的基础技能之一,理解和掌握上述知识点,能够帮助我们有效地进行数据库操作,为后续的项目开发打下坚实的基础。随着经验的增长,你还可以深入学习更高级...

    mysql与java连接的适配包(mysql-connector-java-5.1.47)

    MySQL是世界上最受欢迎的关系型数据库管理系统之一,而Java作为一种广泛应用的编程语言,经常被用来与MySQL进行数据交互。在Java中,我们使用Java Database Connectivity (JDBC) API来连接和操作数据库。MySQL与Java...

    Java数据库编程.ppt

    JDBC是Java运行平台的核心类库之一,它提供了一系列接口,使得Java程序能够连接并操作各种类型的数据库。 9.1 JDBC简介: JDBC是Java中访问数据库的标准接口,它允许开发者编写与数据库无关的代码。这意味着,尽管...

Global site tag (gtag.js) - Google Analytics