Spring注解驱动开发——声明式事物

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rubulai/article/details/80588741

声明式事物:

环境搭建:

1、加入依赖:数据源、数据库驱动、spring-jdbc

<dependency>
	<groupId>com.mchange</groupId>
	<artifactId>c3p0</artifactId>
	<version>0.9.5.2</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.11</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>4.3.17.RELEASE</version>
</dependency>

2、配置类中加入数据源bean和JdbcTemplate的bean

@Configuration
public class TxConfig {

	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("120288");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
		return dataSource;
	}
	
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		return new JdbcTemplate(dataSource());
	}
}

在配置JdbcTemplate时的入参是dataSource(),那不就会调用dataSource()方法重新创建一个不受Spring管理的数据源对象了吗?其实不会的,Spring对@Bean注解的Scope为singleton的方法只会实际调用一次,之后再调用时其实是会返回容器中的对象,该配置也可以像下面这样:

@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) throws Exception{
	return new JdbcTemplate(dataSource);
}

入参的参数Spring会优先从容器中查找,另外需要注意如果使用的数据库驱动比较新时在配置jdbcUrl时需要加上数据库服务器所在的时区:serverTimezone=GMT%2B8(东八区),否则会报异常(The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone)。

3、业务Dao

@Repository
public class UserDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public void insert(String name,int age){
		String sql = "insert into user(user_name,age) values(?,?)";
		jdbcTemplate.update(sql,name,age);
	}
}

sql中可以有占位符,jdbcTemplate的update方法的第一个参数是sql,后面是个可变参数,可以传任何数据来填充占位符

业务Service:

@Service
public class UserService {

	@Autowired
	public UserDao userDao;
	
	public void insert(String name,int age){
		userDao.insert(name, age);
	}
}

测试:

public class MainTest {

	@Test
	public void test1() throws Exception {
		// 1、创建容器对象
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
		UserService bean = context.getBean(UserService.class);
		bean.insert("哼哼", 23);
		context.close();
	}
}

此时的service中是没有事物控制的,也就是说在insert成功之后如果出现异常,依然能够插入成功,比如:

@Service
public class UserService {

	@Autowired
	public UserDao userDao;

	public void insert(String name, int age) {
		userDao.insert(name, age);
		int i = 10 / 0;
		System.out.println(i);
	}
}

那怎么将service中的方法变为事物方法呢,需要给事物方法加个注解@Transactional,仅此还不够还需要开启基于注解版的事物管理功能——在配置类上加注解@EnableTransactionManagement

@Service
public class UserService {

	@Autowired
	public UserDao userDao;

	@Transactional(rollbackFor = Exception.class)
	public void insert(String name, int age) {
		userDao.insert(name, age);
		int i = 10 / 0;
		System.out.println(i);
	}
}

配置类:

@Configuration
@ComponentScan("com.bdm.tx")
@EnableTransactionManagement
public class TxConfig {

	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("120288");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
		return dataSource;
	}
	
	@Bean
	public JdbcTemplate jdbcTemplate(DataSource dataSource) throws Exception{
		return new JdbcTemplate(dataSource);
	}
}

还需要在容器中注册事物管理器:Spring的JdbcTemplate或者mybatis在进行事物整合时使用的事物管理器是DataSourceTransactionManager;JPA或hibernate在进行事物整合时用WebsphereUowTransactionManager,事物管理器管理的是数据源的事物,管理数据源的每一条连接,事物的开启、回滚等

@Configuration
@ComponentScan("com.bdm.tx")
@EnableTransactionManagement
public class TxConfig {

	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("120288");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
		return dataSource;
	}
	
	@Bean
	public JdbcTemplate jdbcTemplate(DataSource dataSource) throws Exception{
		return new JdbcTemplate(dataSource);
	}
	
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
}

如果数据库表的主键是自增的,在出现异常事物回滚后,数据表的主键将不再连续,因为数据回滚前自增的主键值并不会跟着回滚

配置声明式事物的三个步骤:

1、开启注解方式的事物管理功能:配置类加@EnableTransactionManagement

2、配置事物管理器:在配置类中配置PlatformTransactionManager的实现类,注意入参是数据源

@Bean
public PlatformTransactionManager transactionManager() throws Exception{
	return new DataSourceTransactionManager(dataSource());
}

3、事物方法上加注解:@Transactional

猜你喜欢

转载自blog.csdn.net/rubulai/article/details/80588741