2016-10-07 1 views
1

Я использую "Spring TX"v 4.3.2.RELEASE, а также новичок в этом. В моем приложении есть некоторые зависимые задачи, например, в одной транзакции, я хотел бы вставить данные в customer и address, независимо от того, существует ли исключение.Spring Transaction - Как разрешить зависимые транзакции, если кто-то не работает

Данные должны быть сохранены. Здесь мне не нужно заботиться о данных Consistency. Я просто использовал аннотацию @Transactional в моем классе обслуживания, но в этом случае я ожидаю, что данные Customer должны быть сохранены, если есть проблема при сохранении данных address. Я попробовал варианты ниже, но не работал. @Transactional(propagation = Propagation.REQUIRES_NEW). Расскажите, как мы можем это сделать?

код ниже для справки: CustomerService.java

public interface CustomerService { 
    public void createCustomer(Customer cust); 
} 

CustomerServiceImpl.java

public class CustomerServiceImpl implements CustomerService { 

    private CustomerDAO customerDAO; 

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

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

CustomerDAO.java

public interface CustomerDAO { 
    public void create(Customer customer); 
} 

CustomerDAOImpl.java

public class CustomerDAOImpl implements CustomerDAO { 

    private JdbcTemplate jdbcTemplate; 

    public void setDataSource(DataSource dataSource) { 
     jdbcTemplate = new JdbcTemplate(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.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"); 
    } 
} 

пружинно-context.xml

<?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:context="http://www.springframework.org/schema/context" 
    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/context http://www.springframework.org/schema/context/spring-context.xsd 
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> 

    <context:property-placeholder location="classpath:database.properties" /> 

    <!-- 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="${mysql.driver.class.name}" /> 
     <property name="url" value="${mysql.url}" /> 
     <property name="username" value="${mysql.username}" /> 
     <property name="password" value="${mysql.password}" /> 
    </bean> 


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

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

db.sql

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; 

TransactionManagerMain.java

public class TransactionManagerMain { 

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

     CustomerService customerManager = ctx.getBean("customerManager", CustomerServiceImpl.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; 
    } 
} 

Пожалуйста, дайте мне знать, если вам нужна любая другая информация.

Although I get below error, I expect 1st transaction should get committed. 
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:102) 
    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:649) 
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:870) 
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:931) 
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:941) 
    at com.journaldev.spring.jdbc.dao.CustomerDAOImpl.create(CustomerDAOImpl.java:25) 
    at com.journaldev.spring.jdbc.service.CustomerServiceImpl.createCustomer(CustomerServiceImpl.java:20) 
    at com.journaldev.spring.jdbc.service.CustomerServiceImpl$$FastClassBySpringCGLIB$$faf0749.invoke(<generated>) 
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) 
    at com.journaldev.spring.jdbc.service.CustomerServiceImpl$$EnhancerBySpringCGLIB$$9dab5ce1.createCustomer(<generated>) 
    at com.journaldev.spring.jdbc.main.TransactionManagerMain.main(TransactionManagerMain.java:18) 
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:877) 
    at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:870) 
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633) 
    ... 16 more 

ответ

1

Прежде всего, ваша ошибка не имеет отношения к обработке транзакций. Читайте его сообщение:

Data truncation: Data too long for column 'address' 

Так, "Albany Dr, San Jose, CA 95129" слишком долго, чтобы поместиться в столбце адреса.

Что касается вашего вопроса, вы используете единую транзакцию для сохранения клиента и его адреса, поэтому при возникновении исключения все будет отменено: это определение транзакции. Если вы хотите, чтобы клиент был совершен, даже если сбой ввода адреса, вам нужны две транзакции: одна, которая сохраняет клиента и совершает, а вторая - сохраняет адрес и фиксирует его.

+0

Hi JB - Если я использовал '@Transactional (распространение = распространение.SUPPORTS)', он позволяет мне сохранять данные клиента в таблицу, хотя есть проблема при сохранении данных в адресе. Это то, что я хочу, с приведенной выше аннотацией данные сохраняются в таблице клиентов. Не уверен, что такое пропаганда? SUPPORTS? –

+0

http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html#SUPPORTS. Вероятно, это работает случайно, потому что при отсутствии транзакции соединение автоматически фиксируется. Как я уже сказал, вместо этого у вас должно быть две транзакции. –

0

Чтобы сохранить их независимо друг от друга, вам необходимо держать их в разных транзакциях.Вам необходимо будет сделать что-то подобное с классом Dao:

public class CustomerDAOImpl implements CustomerDAO { 

    private JdbcTemplate jdbcTemplate; 

    public void setDataSource(DataSource dataSource) { 
     jdbcTemplate = new JdbcTemplate(dataSource); 
    } 

    @Override 
    @Transactional(propagation = Propagation.REQUIRES_NEW) 
    public void createCustomer(Customer customer) { 
     String queryCustomer = "insert into Customer (id, name) values (?,?)"; 
     jdbcTemplate.update(queryCustomer, new Object[] { customer.getId(), customer.getName() }); 
     System.out.println("Inserted into Customer Table Successfully"); 
    } 

    @Override 
    @Transactional(propagation = Propagation.REQUIRES_NEW) 
    public void createAddress(Customer customer) { 
     String queryAddress = "insert into Address (id, address,country) values (?,?,?)"; 
     jdbcTemplate.update(queryAddress, new Object[] { customer.getId(), customer.getAddress().getAddress(),customer.getAddress().getCountry() }); 
     System.out.println("Inserted into Address Table Successfully"); 
    } 
} 

И удалите транзакционную аннотацию из класса обслуживания. При этом у вас будет две транзакции, начинающиеся с уровня Dao для клиента и адреса, и любая ошибка с одним не откат другого.

Смежные вопросы