spring事务 jdbc_Spring事务管理示例JDBC

spring事务 jdbc

Spring Transaction Management is one of the most widely used and important feature of Spring framework. Transaction Management is a trivial task in any enterprise application. We have already learned how to use JDBC API for Transaction Management. Spring provides extensive support for transaction management and help developers to focus more on business logic rather than worrying about the integrity of data incase of any system failures.

Spring事务管理是Spring框架中使用最广泛,最重要的功能之一。 在任何企业应用程序中,事务管理都是一项琐碎的任务。 我们已经学习了如何使用JDBC API进行事务管理 。 Spring为事务管理提供了广泛的支持,并帮助开发人员将更多的精力放在业务逻辑上,而不用担心任何系统故障时数据的完整性。

Spring交易管理 (Spring Transaction Management)

Some of the benefits of using Spring Transaction Management are:

使用Spring事务管理的一些好处是:

  1. Support for Declarative Transaction Management. In this model, Spring uses AOP over the transactional methods to provide data integrity. This is the preferred approach and works in most of the cases.

    支持声明式事务管理。 在此模型中,Spring在事务方法上使用AOP来提供数据完整性。 这是首选方法,并且在大多数情况下都有效。
  2. Support for most of the transaction APIs such as JDBC, Hibernate, JPA, JDO, JTA etc. All we need to do is use proper transaction manager implementation class. For example org.springframework.jdbc.datasource.DriverManagerDataSource for JDBC transaction management and org.springframework.orm.hibernate3.HibernateTransactionManager if we are using Hibernate as ORM tool.

    支持大多数事务API,例如JDBC,Hibernate,JPA,JDO,JTA等。我们需要做的就是使用适当的事务管理器实现类。 例如org.springframework.jdbc.datasource.DriverManagerDataSource为JDBC事务管理和org.springframework.orm.hibernate3.HibernateTransactionManager如果我们使用Hibernate作为ORM工具。
  3. Support for programmatic transaction management by using TransactionTemplate or PlatformTransactionManager implementation.

    通过使用TransactionTemplatePlatformTransactionManager实现,支持程序化事务管理。

Most of the features that we would want in a transaction manager is supported by Declarative transaction management, so we would use this approach for our example project.

声明式事务管理支持我们在事务管理器中需要的大多数功能,因此我们将在示例项目中使用这种方法。

Spring事务管理JDBC示例 (Spring Transaction Management JDBC Example)

We will create a simple Spring JDBC project where we will update multiple tables in a single transaction. The transaction should commit only when all the JDBC statements execute successfully otherwise it should rollback to avoid data inconsistency.

我们将创建一个简单的Spring JDBC项目,在其中我们将在单个事务中更新多个表。 仅当所有JDBC语句成功执行时,事务才应提交,否则应回滚以避免数据不一致。

If you know JDBC transaction management, you might argue that we can get do it easily by setting auto-commit to false for the connection and based on the result of all the statements, either commit or rollback the transaction. Obviously we can do it, but that will result in a lot of boiler-plate code just for transaction management. Also the same code will present in all the places where we are looking for transaction management, causing tightly coupled and non-maintainable code.

如果您了解JDBC事务管理,您可能会说我们可以通过将连接的auto-commit设置为false并基于所有语句的结果(提交或回滚事务)来轻松实现。 显然,我们可以做到这一点,但是这将导致大量用于交易管理的样板代码。 同样,在我们正在寻找事务管理的所有地方都将出现相同的代码,从而导致紧密耦合且不可维护的代码。

Spring declarative transaction management addresses these concerns by using Aspect Oriented Programming to achieve loose coupling and avoid boiler-plate code in our application. Let’s see how Spring does it with a simple example.

Spring声明式事务管理通过使用面向方面的编程来实现这些耦合,从而实现松散耦合并避免在我们的应用程序中使用样板代码来解决这些问题。 让我们用一个简单的例子看看Spring是如何做到的。

Before we jump into our Spring project, let’s do some database setup for our use.

在进入Spring项目之前,让我们进行一些数据库设置以供使用。

Spring事务管理–数据库设置 (Spring Transaction Management – Database Setup)

We will create two tables for our use and update both of them in a single transaction.

我们将创建两个表供我们使用,并在单个事务中更新它们。

CREATE TABLE `Customer` (
  `id` int(11) unsigned NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
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;

We could define foreign-key relationship here from Address id column to Customer id column, but for simplicity I am not having any constraint defined here.

我们可以在此处从地址ID列到客户ID列定义外键关系,但是为简单起见,我在这里没有定义任何约束。

Our Database setup is ready for spring transaction management project, lets create a simple Spring Maven Project in the Spring Tool Suite. Our final project structure will look like below image.

我们的数据库设置已准备就绪,可以用于Spring事务管理项目,可以在Spring Tool Suite中创建一个简单的Spring Maven项目。 我们的最终项目结构将如下图所示。

Let’s look into each of the pieces one by one, together they will provide a simple spring transaction management example with JDBC.

让我们逐一研究各个部分,它们一起将提供一个使用JDBC的简单Spring事务管理示例。

Spring交易管理– Maven依赖关系 (Spring Transaction Management – Maven Dependencies)

Since we are using JDBC API, we would have to include spring-jdbc dependency in our application. We would also need MySQL database driver to connect to mysql database, so we will include mysql-connector-java dependency too.

由于我们使用的是JDBC API,因此我们必须在应用程序中包含spring-jdbc依赖项。 我们还需要MySQL数据库驱动程序来连接到mysql数据库,因此我们还将包括mysql-connector-java依赖项。

spring-tx artifact provides transaction management dependencies, usually it’s included automatically by STS but if it’s not then you need to include it too. You might see some other dependencies for logging and unit testing, however we will not be using any of them. Our final pom.xml file looks like below code.

spring-tx构件提供了事务管理依赖关系,通常它由STS自动包含,但是如果没有,那么您也需要包含它。 您可能会看到其他一些用于日志记录和单元测试的依赖项,但是我们将不再使用它们。 我们最终的pom.xml文件看起来像下面的代码。

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.springframework.samples</groupId>
	<artifactId>SpringJDBCTransactionManagement</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>

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

		<!-- Spring -->
		<spring-framework.version>4.0.2.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>

		<!-- 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>
</project>

I have updated the Spring versions to the latest one as of today. Make sure MySQL database driver is compatible with your mysql installation.

到目前为止,我已经将Spring版本更新为最新版本。 确保MySQL数据库驱动程序与您的mysql安装兼容。

Spring交易管理–模型类 (Spring Transaction Management – Model Classes)

We will create two Java Beans, Customer and Address that will map to our tables.

我们将创建两个Java Bean,分别是Customer和Address,它们将映射到我们的表。

package com.journaldev.spring.jdbc.model;

public class Address {

	private int id;
	private String address;
	private String country;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	
}
package com.journaldev.spring.jdbc.model;

public class Customer {

	private int id;
	private String name;
	private Address address;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	
}

Notice that Customer bean has Address as one of it’s variables. When we will implement DAO for Customer, we will get data for both customer and address table and we will execute two separate insert queries for these tables and that’s why we need transaction management to avoid data inconsistency.

注意,Customer bean的地址之一是Address。 当我们为客户实现DAO时,我们将同时获取客户表和地址表的数据,并且将对这些表执行两个单独的插入查询,这就是为什么我们需要事务管理以避免数据不一致的原因。

Spring交易管理– DAO实施 (Spring Transaction Management – DAO Implementation)

Let’s implement the DAO for Customer bean, for simplicity we will just have one method to insert record in both customer and address tables.

让我们实现DAO for Customer Bean,为简单起见,我们只有一种方法可以在客户表和地址表中插入记录。

package com.journaldev.spring.jdbc.dao;

import com.journaldev.spring.jdbc.model.Customer;

public interface CustomerDAO {

	public void create(Customer customer);
}
package com.journaldev.spring.jdbc.dao;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;

import com.journaldev.spring.jdbc.model.Customer;

public class CustomerDAOImpl implements CustomerDAO {

	private DataSource dataSource;

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

	@Override
	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");
	}

}

Notice that CustomerDAO implementation is not taking care of transaction management. This way we are achieving separation of concerns because sometimes we get DAO implementations from third party and we don’t have control on these classes.

请注意,CustomerDAO实施并未处理事务管理。 这样,我们就可以实现关注点分离,因为有时我们会从第三方获得DAO实现,而我们无法控制这些类。

Spring声明式事务管理–服务 (Spring Declarative Transaction Management – Service)

Let’s create a Customer Service that will use the CustomerDAO implementation and provide transaction management when inserting records in the customer and address tables in a single method.

让我们创建一个客户服务,该客户服务将使用CustomerDAO实现并在以一种方法在客户表和地址表中插入记录时提供事务管理。

package com.journaldev.spring.jdbc.service;

import com.journaldev.spring.jdbc.model.Customer;

public interface CustomerManager {

	public void createCustomer(Customer cust);
}
package com.journaldev.spring.jdbc.service;

import org.springframework.transaction.annotation.Transactional;

import com.journaldev.spring.jdbc.dao.CustomerDAO;
import com.journaldev.spring.jdbc.model.Customer;

public class CustomerManagerImpl implements CustomerManager {

	private CustomerDAO customerDAO;

	public void setCustomerDAO(CustomerDAO customerDAO) {
		this.customerDAO = customerDAO;
	}

	@Override
	@Transactional
	public void createCustomer(Customer cust) {
		customerDAO.create(cust);
	}

}

If you notice the CustomerManager implementation, it’s just using CustomerDAO implementation to create the customer but provide declarative transaction management through annotating createCustomer() method with @Transactional annotation. That’s all we need to do in our code to get the benefits of Spring transaction management.

如果您注意到CustomerManager实现,它只是使用CustomerDAO实现来创建客户,而是通过使用@Transactional注释对createCustomer()方法进行注释来提供声明性事务管理。 这就是我们代码中需要做的一切,以获得Spring事务管理的好处。

@Transactional annotation can be applied over methods as well as whole class. If you want all your methods to have transaction management features, you should annotate your class with this annotation. Read more about annotations at Java Annotations Tutorial.
The only part remaining is wiring spring beans to get spring transaction management example to work.

@Transactional注释可以应用于方法以及整个类。 如果希望所有方法都具有事务管理功能,则应使用此批注对类进行批注。 在Java Annotations Tutorial中阅读有关注释的更多信息。
剩下的唯一部分是接线Spring bean,以使Spring事务管理示例正常工作。

Spring事务管理– Bean配置 (Spring Transaction Management – Bean Configuration)

Create a Spring Bean Configuration file with name as “spring.xml”. We will use this in our test program to wire spring beans and execute our JDBC program to test transaction management.

创建一个名称为“ spring.xml”的Spring Bean配置文件。 我们将在测试程序中使用它来连接spring bean和执行JDBC程序来测试事务管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context"
	xmlns:tx="https://www.springframework.org/schema/tx"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.0.xsd
		https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<!-- Enable Annotation based Declarative Transaction Management -->
	<tx:annotation-driven proxy-target-class="true"
		transaction-manager="transactionManager" />

	<!-- Creating TransactionManager Bean, since JDBC we are creating of type 
		DataSourceTransactionManager -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!-- MySQL DB DataSource -->
	<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/TestDB" />
		<property name="username" value="pankaj" />
		<property name="password" value="pankaj123" />
	</bean>

	<bean id="customerDAO" class="com.journaldev.spring.jdbc.dao.CustomerDAOImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="customerManager" class="com.journaldev.spring.jdbc.service.CustomerManagerImpl">
		<property name="customerDAO" ref="customerDAO"></property>
	</bean>

</beans>

Important points to note in the spring bean configuration file are:

Spring bean配置文件中需要注意的重要事项是:

  • tx:annotation-driven element is used to tell Spring context that we are using annotation based transaction management configuration. transaction-manager attribute is used to provide the transaction manager bean name. transaction-manager default value is transactionManager but I am still having it to avoid confusion. proxy-target-class attribute is used to tell Spring context to use class based proxies, without it you will get runtime exception with message such as Exception in thread “main” org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named ‘customerManager’ must be of type [com.journaldev.spring.jdbc.service.CustomerManagerImpl], but was actually of type [com.sun.proxy.$Proxy6]

    tx:annotation-driven元素用于告诉Spring上下文我们正在使用基于注释的事务管理配置。 transaction-manager属性用于提供事务管理器Bean名称。 transaction-manager的默认值是transactionManager,但我仍然可以避免混淆。 proxy-target-class属性用于告诉Spring上下文使用基于类的代理,没有它,您将在消息中获得运行时异常,例如线程“ main”中的异常org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为“ customerManager”的Bean必须为[com.journaldev.spring.jdbc.service.CustomerManagerImpl]类型,但实际上为[com.sun.proxy。$ Proxy6]类型
  • Since we are using JDBC, we are creating transactionManager bean of type org.springframework.jdbc.datasource.DataSourceTransactionManager. This is very important and we should use proper transaction manager implementation class based on our transaction API use.

    由于使用的是JDBC,因此我们将创建org.springframework.jdbc.datasource.DataSourceTransactionManager类型的transactionManager bean。 这非常重要,我们应该根据交易API的使用情况使用适当的交易管理器实现类。
  • dataSource bean is used to create the DataSource object and we are required to provide the database configuration properties such as driverClassName, url, username and password. Change these values based on your local settings.

    dataSource bean用于创建DataSource对象,我们需要提供数据库配置属性,例如driverClassName,url,用户名和密码。 根据您的本地设置更改这些值。
  • We are injecting dataSource into customerDAO bean. Similarly we are injecting customerDAO bean into customerManager bean definition.

    我们正在将dataSource注入customerDAO bean。 同样,我们将customerDAO bean注入到customerManager bean定义中。

Our setup is ready, let’s create a simple test class to test our transaction management implementation.

我们的设置已经准备就绪,让我们创建一个简单的测试类来测试我们的事务管理实现。

package com.journaldev.spring.jdbc.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.jdbc.model.Address;
import com.journaldev.spring.jdbc.model.Customer;
import com.journaldev.spring.jdbc.service.CustomerManager;
import com.journaldev.spring.jdbc.service.CustomerManagerImpl;

public class TransactionManagerMain {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
				"spring.xml");

		CustomerManager customerManager = ctx.getBean("customerManager",
				CustomerManagerImpl.class);

		Customer cust = createDummyCustomer();
		customerManager.createCustomer(cust);

		ctx.close();
	}

	private static Customer createDummyCustomer() {
		Customer customer = new Customer();
		customer.setId(2);
		customer.setName("Pankaj");
		Address address = new Address();
		address.setId(2);
		address.setCountry("India");
		// setting value more than 20 chars, so that SQLException occurs
		address.setAddress("Albany Dr, San Jose, CA 95129");
		customer.setAddress(address);
		return customer;
	}

}

Notice that I am explicitly setting address column value too long so that we will get exception while inserting data into Address table.

请注意,我显式设置的地址列值太长,以至于在将数据插入到地址表中时会出现异常。

Now when we run our test program, we get following output.

现在,当我们运行测试程序时,我们得到以下输出。

Mar 29, 2014 7:59:32 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Sat Mar 29 19:59:32 PDT 2014]; root of context hierarchy
Mar 29, 2014 7:59:32 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Mar 29, 2014 7:59:32 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Inserted into Customer Table Successfully
Mar 29, 2014 7:59:32 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
Mar 29, 2014 7:59:32 PM org.springframework.jdbc.support.SQLErrorCodesFactory <init>
INFO: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
Exception in thread "main" org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [insert into Address (id, address,country) values (?,?,?)]; Data truncation: Data too long for column 'address' at row 1; nested exception is com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'address' at row 1
	at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:100)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
	at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:907)
	at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:968)
	at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:978)
	at com.journaldev.spring.jdbc.dao.CustomerDAOImpl.create(CustomerDAOImpl.java:27)
	at com.journaldev.spring.jdbc.service.CustomerManagerImpl.createCustomer(CustomerManagerImpl.java:19)
	at com.journaldev.spring.jdbc.service.CustomerManagerImpl$$FastClassBySpringCGLIB$$84f71441.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
	at com.journaldev.spring.jdbc.service.CustomerManagerImpl$$EnhancerBySpringCGLIB$$891ec7ac.createCustomer(<generated>)
	at com.journaldev.spring.jdbc.main.TransactionManagerMain.main(TransactionManagerMain.java:20)
Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'address' at row 1
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2939)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1623)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1715)
	at com.mysql.jdbc.Connection.execSQL(Connection.java:3249)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1268)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1541)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1455)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1440)
	at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:914)
	at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:907)
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:642)
	... 16 more

Notice the log message says that data inserted into customer table successfully but exception thrown by MySQL database driver clearly says that value is too long for the address column. Now if you will check the Customer table, you won’t find any row there that means that transaction is rolled back completely.

请注意,该日志消息指出已成功将数据插入到客户表中,但MySQL数据库驱动程序引发的异常清楚地表明该值对于地址列而言太长。 现在,如果您将检查Customer表,那么您将在该表中找不到任何行,这意味着该事务已完全回滚。

If you are wondering where the transaction management magic is happening, look at the logs carefully and notice the AOP and Proxy classes created by Spring framework. Spring framework is using Around advice to generate a proxy class for CustomerManagerImpl and only committing the transaction if the method returns successfully. If there is any exception, it’s just rolling back the whole transaction. I would suggest you to read Spring AOP Example to learn more about Aspect Oriented Programming model.

如果您想知道事务管理的神奇力量在哪里发生,请仔细查看日志并注意Spring框架创建的AOP和Proxy类。 Spring框架使用Around建议为CustomerManagerImpl生成代理类,并且仅在方法成功返回时才提交事务。 如果有任何异常,它只是回滚整个事务。 我建议您阅读Spring AOP示例以了解有关面向方面的编程模型的更多信息。

That’s all for Spring Transaction Management Example, download the sample project from below link and play around with it to learn more.

这就是Spring事务管理示例的全部内容,请从下面的链接下载示例项目,并进行试用以了解更多信息。

翻译自: https://www.journaldev.com/2603/spring-transaction-management-jdbc-example

spring事务 jdbc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于Java Spring框架中配置JDBC连接DataSource的问题。在Spring中,我们可以使用以下配置来连接数据源: 1. 配置数据源 ``` <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/test"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> ``` 在这个配置中,我们使用了`DriverManagerDataSource`来创建数据源,你也可以使用其他的数据源,比如`BasicDataSource`、`C3P0DataSource`、`HikariDataSource`等。 2. 配置JdbcTemplate ``` <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> ``` 在这个配置中,我们使用了`JdbcTemplate`来执行SQL语句,这个类提供了一系列的方法,比如`queryForObject`、`queryForList`、`update`等,可以方便地执行SQL语句。 3. 使用JdbcTemplate ``` @Autowired private JdbcTemplate jdbcTemplate; public void someMethod() { String sql = "SELECT * FROM user WHERE id=?"; User user = jdbcTemplate.queryForObject(sql, new Object[]{1}, new BeanPropertyRowMapper<>(User.class)); } ``` 在这个示例中,我们使用了`JdbcTemplate`的`queryForObject`方法来执行SQL语句,并将结果转换为一个`User`对象。 希望这个回答能够帮到你,如果还有问题,可以继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值