我试图在桌子上写字时把锁放在桌子上,如果之间发生了什么事情,那么回滚。
尝试转换下面的代码
lock table test_g1 read;
lock table test_g write;
-- BEGIN;
START TRANSACTION;
insert into test_g1 values(143);
insert into test_g values(145);
select * from test_g1;
select * from test_g;
Rollback;
select * from test_g;
unlock tables;
如何将上面的代码转换为@Transactional spring jdbcTemplate代码?
@Transactional(rollbackFor={DataAccessException.class})
public void Test(){
jdbcTemplate.execute("insert into test1 (id, nam) values (4, 'A')");
throw new DataAccessException("error") {
};
}
这里我试图抛出错误,所以insert语句应该回滚,但它没有发生。
由于
修改-1 我附上代码,我到底在做什么
在JdbcDaoImpl.java中,我在Test()上面提到了我的问题。
App.java
package com.cgiri.javabrains.Spring4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.annotation.Transactional;
public class App
{
public static void main( String[] args )
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
App2 app2 = ctx.getBean("app2",App2.class);
app2.call();
}
}
App2.java
package com.cgiri.javabrains.Spring4;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class App2 {
@Autowired
private ApplicationContext ctx = null;
JdbcDaoImpl jdbcDaoImpl ;
public void call( )
{
jdbcDaoImpl = ctx.getBean("jdbcDaoImpl",JdbcDaoImpl.class);
System.out.println(jdbcDaoImpl.getCount());
try{
jdbcDaoImpl.Test();
}catch(Exception e)
{
}
System.out.println(jdbcDaoImpl.getCount());
}
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.ctx = context;
}
}
JdbcDaoImpl.java
package com.cgiri.javabrains.Spring4;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
@Transactional
public class JdbcDaoImpl {
private JdbcTemplate jdbcTemplate;
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int getCount() {
String sql = "SELECT COUNT(*) FROM test1";
// jdbcTemplate.setDataSource(getDataSource());
return jdbcTemplate.queryForObject(sql, Integer.class);
}
public void crateTable() {
String sql = "create table if not exists test1 (id integer, nam char(50))";
jdbcTemplate.execute(sql);
jdbcTemplate.execute("insert into test1 (id, nam) values (1, 'A')");
int count = jdbcTemplate.queryForObject("select count(*) from test1",Integer.class);
System.out.println(count);
}
/**** This is the point where i am trying to rollback insert query ,but it's not happening , instead it's inserting the data into the table and just throwing exception , rollback is not happeneing ****/
@Transactional(rollbackFor={DataAccessException.class})
public void Test(){
jdbcTemplate.execute("insert into test1 (id, nam) values (4, 'A')");
throw new DataAccessException("error") {
};
}
}
AppConfig.java
package com.cgiri.javabrains.Spring4;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionTemplate;
@Configuration
@ComponentScan({ "com.cgiri.javabrains.Spring4" })
@PropertySource("classpath:db.properties")
public class AppConfig {
private JdbcTemplate jdbcTemplate;
private TransactionTemplate transactionTemplate;
@Autowired
private Environment env;
@Bean
public BasicDataSource getBasicDataSource()
{
BasicDataSource dao = new BasicDataSource();
dao.setDriverClassName(env.getProperty("db.driverClassName"));
dao.setUrl(env.getProperty("db.url"));
dao.setUsername(env.getProperty("db.userName"));
dao.setPassword(env.getProperty("db.password"));
dao.setInitialSize(2);
dao.setMaxActive(5);
return dao;
}
@Bean
public DataSourceTransactionManager getTransactionManager(BasicDataSource dataSource) {
DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource);
return manager;
}
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
}
为了在DML查询期间锁定表,如果有两个或更多人同时在表上更新,这个锁定机制由mysql服务器负责,或者我们必须单独配置我们为事务做的方式?
谢谢
答案 0 :(得分:1)
如果您不想使用@Transactional
,那么您可以尝试使用TransactionTemplate
之类的内容:
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
@Component
public SimpleDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionTemplate transactionTemplate;
private void executeTransactionWithoutResult(DbTransactionTask dbTask) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
dbTask.executeTask();
}
});
}
public void test() {
DbTransactionTask dbTask = new DbTransactionTask() {
@Override
public void executeTask() {
try {
jdbcTemplate.execute("LOCK TABLES Entry WRITE;");
jdbcTemplate.execute("...");
jdbcTemplate.execute("...");
jdbcTemplate.execute("UNLOCK TABLES;")
} catch (Exception e) {
// Cause rollback of transaction
throw new RuntimeException("Reverting DB operations: " + e.getClass().getSimpleName() + " - " + e.getMessage(), e);
}
}
};
executeTransactionWithoutResult(dbTask);
}
abstract class DbTransactionTask { public abstract void executeTask(); }
}
编辑:使用@Transactional
您可以尝试以下内容:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import dao.EntryDao;
@SpringBootApplication
public class SpringTransactional {
private ConfigurableApplicationContext springContext;
@Autowired
private EntryDao dao;
public void init() {
springContext = SpringApplication.run(SpringTransactional.class);
springContext.getAutowireCapableBeanFactory().autowireBean(this);
}
public static void main(String[] args) {
SpringTransactional st = new SpringTransactional();
try {
st.init();
dao.db_transaction_test();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
st.springContext.close();
}
}
}
EntryDao 是:
package dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* DB creation and schema:
* CREATE DATABASE db_name;
* CREATE USER db_username;
* <p>
* USE db_name;
* GRANT ALL ON db_name.* TO db_username;
* <p>
* SET PASSWORD FOR spz = PASSWORD('username123');
* FLUSH PRIVILEGES;
* <p>
* CREATE TABLE Entry (
* entry_ID INT NOT NULL AUTO_INCREMENT,
* name TEXT NOT NULL,
* <p>
* PRIMARY KEY (entry_ID)
* );
*/
@Component
public class EntryDao {
/**
* application.properties:
* spring.datasource.driver-class-name = com.mysql.jdbc.Driver
* spring.datasource.url = jdbc:mysql://localhost:3306/db_name?useSSL=false&serverTimezone=UTC
* spring.datasource.username = db_username
* spring.datasource.password = username123
*/
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void db_transaction_test() {
jdbcTemplate.execute("LOCK TABLES Entry WRITE;");
for (int i = 0; i < 10; i++) {
try {
int entry_name = getEntryId("entry_" + i);
System.out.println("Created entry id=" + entry_name);
} catch (EntryDao.DaoException e) {
e.printStackTrace();
}
if (i == 5) {
throw new RuntimeException("Testing data upload procedure break.");
}
}
jdbcTemplate.execute("UNLOCK TABLES;")
}
public int getEntryId(String entryName) throws DaoException {
List<DbEntry> dbEntries = retrieveEntriesFor(entryName);
if (dbEntries.size() == 1) {
return dbEntries.get(0).getEntry_ID();
} else if (dbEntries.size() == 0) {
String sqlInsert = "INSERT INTO Entry (name) VALUES (?)";
jdbcTemplate.update(sqlInsert, entryName);
dbEntries = retrieveEntriesFor(entryName);
if (dbEntries.size() == 1) {
return dbEntries.get(0).getEntry_ID();
} else {
throw new DaoException("Invalid results amount received after creating new (" + dbEntries.size() + ") when getting entry for name: " + entryName);
}
} else {
throw new DaoException("Invalid results amount received (" + dbEntries.size() + ") when getting entry for name: " + entryName);
}
}
private List<DbEntry> retrieveEntriesFor(String entryName) {
return jdbcTemplate.query("SELECT * FROM Entry WHERE name=?;", (ResultSet result, int rowNum) -> unMarshal(result), entryName);
}
private DbEntry unMarshal(ResultSet result) throws SQLException {
DbEntry dbEntry = new DbEntry();
dbEntry.setEntry_ID(result.getInt("entry_ID"));
dbEntry.setName(result.getString("name"));
return dbEntry;
}
public class DbEntry {
private int entry_ID;
private String name;
int getEntry_ID() { return entry_ID; }
void setEntry_ID(int entry_ID) { this.entry_ID = entry_ID; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public class DaoException extends Throwable { DaoException(String err_msg) { super(err_msg); } }
}