Spring框架 XML配置事務控制的步驟操作

在這裡插入圖片描述

基於 XML 的聲明式事務控制

1.環境搭建

拷貝必要的 jar 包到工程的 lib 目錄

在這裡插入圖片描述

2.創建 spring 的配置文件並導入約束

這裡直接給出本次測試的全部XML配置,具體細節在後面依次介紹。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	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/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd 
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx.xsd ">
	<!-- 配置連接池對象 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybase2" />
		<property name="user" value="root" />
		<property name="password" value="Hudie" />
	</bean>
	
	<!-- 配置JdbcTemplate模板對象 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- dao -->
	<bean id="userDao" class="com.gql.dao.UserDaoImp">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	<!-- service -->
	<bean id="userService" class="com.gql.service.UserServiceImp">
		<property name="userDao" ref="userDao"></property>
	</bean>
	
	<!-- 事務類/切面 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 
		通知: 
		1.告訴Spring容器采用哪種事務管理機制. 
		2.告訴Spring容器目標方法采用什麼樣的事務處理策略. 
	-->
	<tx:advice id="tx" transaction-manager="transactionManager">
		<tx:attributes>
				<!-- 
					name 規定目標方法 
					isolation 事務隔離級別,默認是default 
					propagation 傳播機制,默認是REQUIREL 
				-->
			<tx:method name="save" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
			<tx:method name="up*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
			<tx:method name="de*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
			<tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" />
		</tx:attributes>
	</tx:advice>
	<aop:config>
		<aop:pointcut expression="execution (* com.gql.service.UserServiceImp.*(..))" id="point" />
		<aop:advisor advice-ref="tx" pointcut-ref="point" />
	</aop:config>
</beans>

3.準備數據庫表和實體類

user數據庫表

create database mybase2;
USE mybase2;
CREATE TABLE `user` (
	`id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
	`name` VARCHAR(20) NOT NULL DEFAULT '0',
	`age` INT(10) NOT NULL DEFAULT '0',
	PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
INSERT INTO user values(NULL,'周冬雨',21);
INSERT INTO user values(NULL,'馬冬梅',18);
INSERT INTO user values(NULL,'馬西梅',19);

User實體類

package com.gql.entity;
import java.io.Serializable;
/**
 * 類說明:
 *		User實體類
 * @guoqianliang1998.
 */
public class User implements Serializable {
	/**
	 * 生成序列號
	 */
	private static final long serialVersionUID = -4492760954899814333L;
	private int id;
	private String name;
	private int age;
	
	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

4.業務層接口與實現類

業務層接口

package com.gql.service;
import java.util.List;
import com.gql.entity.User;
/**
 * 類說明:
 *		業務層接口
 * @guoqianliang1998.
 */
public interface UserService {
	void save(User user);
	void update(int id, User user);
	void delete(int id);
	User getUser(int id);
	List<User> getUserList(int[] ids);
	
	List<User> getUserList();
}

業務層實現類

package com.gql.service;
import java.util.List;
import com.gql.dao.UserDao;
import com.gql.entity.User;
/**
 * 類說明:
 *		業務層實現類
 * @guoqianliang1998.
 */
public class UserServiceImp implements UserService {
	private UserDao userDao;
	
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	@Override
	public void save(User user) {
		userDao.save(user);
		int i = 1/0;
	}
	@Override
	public void update(int id, User user) {
		userDao.update(id, user);
	}
	@Override
	public void delete(int id) {
		userDao.delete(id);
	}
	@Override
	public User getUser(int id) {
		User user = userDao.getUser(id);
		return user;
	}
	@Override
	public List<User> getUserList(int[] ids) {
		List<User> userList = userDao.getUserList(ids);
		return userList;
	}
	@Override
	public List<User> getUserList() {
		List<User> list = userDao.getUserList();
		return list;
	}
}

5.數據訪問層接口與實現類

數據訪問層接口

package com.gql.dao;
import java.util.List;
import com.gql.entity.User;
/**
 * 類說明: 
 * 		數據訪問層接口 
 * @guoqianliang1998.
 */
public interface UserDao {
	void save(User user);
	void update(int id, User user);
	void delete(int id);
	User getUser(int id);
	List<User> getUserList(int[] ids);
	
	List<User> getUserList();	
}

數據訪問層實現類

package com.gql.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import com.gql.RowMapper.UserRowMapper;
import com.gql.entity.User;
/**
 * 類說明: 
 * 		數據訪問層實現類 
 * @guoqianliang1998.
 */
public class UserDaoImp implements UserDao {
	private JdbcTemplate jdbcTemplate;
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	@Override
	public void save(User user) {
		String sql = "INSERT INTO user values(NULL,?,?)";
		jdbcTemplate.update(sql, user.getName(), user.getAge());
	}
	@Override
	public void update(int id, User user) {
		String sql = "update user set name=?,age=? WHERE id = ?";
		jdbcTemplate.update(sql, user.getName(), user.getAge(), id);
	}
	@Override
	public void delete(int id) {
		String sql = "DELETE FROM user WHERE id = ?;";
		jdbcTemplate.update(sql, id);
	}
	@Override
	public User getUser(int id) {
		String sql = "select * from user where id = ?";
		User user = jdbcTemplate.queryForObject(sql, new RowMapper<User>() {
			@Override
			public User mapRow(ResultSet rs, int rowNum) throws SQLException {
				User user = new User();
				user.setId(rs.getInt(1));
				user.setName(rs.getString(2));
				user.setAge(rs.getInt(3));
				return user;
			}
		}, id);
		return user;
	}
	@Override
	public List<User> getUserList(int[] ids) {
		String sql = "select * from user where id in(:ids)";
		
		NamedParameterJdbcTemplate n = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
		Map<String,Object> paramMap = new HashMap<String,Object>();
		List list = new ArrayList();
		for (int i = 0; i < ids.length; i++) {
			list.add(ids[i]);
		}
		paramMap.put("ids", list);
		List<User> userList = n.query(sql, paramMap, new RowMapper<User>(){
			@Override
			public User mapRow(ResultSet rs, int rowNum) throws SQLException {
				User user = new User();
				user.setId(rs.getInt(1));
				user.setName(rs.getString(2));
				user.setAge(rs.getInt(3));
				return user;
			}
		});
		return userList;
		
//		第二種寫法↓↓↓
//		StringBuilder sb = new StringBuilder();
//		sb.append("SELECT * FROM user WHERE id = ?");
//		for(int i=0;i<ids.length-1;i++){
//			sb.append(" or id = ?");
//		}
//		Integer[] in = new Integer[ids.length];
//		for(int i=0;i<ids.length;i++){
//			in[i] = ids[i];
//		}
//		Object[] args = in;
//		List<User> userList = jdbcTemplate.query(sb.toString(),args,new RowMapper() {
//			
//			@Override
//			public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
//				User user = new User();
//				user.setId(rs.getInt(1));
//				user.setName(rs.getString(2));
//				user.setAge(rs.getInt(3));
//				return user;
//			}	
//		});
//		return userList;
	}
	@Override
	public List<User> getUserList() {
		String sql = "select * from user";
		List<User> list = jdbcTemplate.query(sql, new UserRowMapper());
		return list;
	}
}

6.配置c3p0數據源/業務層/數據訪問層

配置c3p0數據源

	<!-- 配置連接池對象 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybase2" />
		<property name="user" value="root" />
		<property name="password" value="Hudie" />
	</bean>
		<!-- 配置JdbcTemplate模板對象 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

業務層

	<!-- service -->
	<bean id="userService" class="com.gql.service.UserServiceImp">
		<property name="userDao" ref="userDao"></property>
	</bean>

數據訪問層

	<!-- dao -->
	<bean id="userDao" class="com.gql.dao.UserDaoImp">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>

7.配置事務管理器

	<!-- 事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 註入 DataSource-->
		<property name="dataSource" ref="dataSource"></property>
	</bean>

8.配置事務的通知

事務的通知:

  • 配置事務的通知來引用事務管理器
  • 告訴Spring容器采用哪種事務管理機制.
  • 告訴Spring容器目標方法采用什麼樣的事務處理策略.
	<!-- 
		事務的通知: 
		1.告訴Spring容器采用哪種事務管理機制. 
		2.告訴Spring容器目標方法采用什麼樣的事務處理策略. 
	-->
	<tx:advice id="tx" transaction-manager="transactionManager">
		<tx:attributes>
				<!-- 
					name 規定目標方法 
					isolation 事務隔離級別,默認是default 
					propagation 傳播機制,默認是REQUIREL 
				-->
			<tx:method name="save" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
		</tx:attributes>
	</tx:advice>

通知內配置事務的屬性

屬性 說明
read-only 是否是隻讀事務。默認 false,不隻讀。
isolation 指定事務的隔離級別。默認值是使用數據庫的默認隔離級別。
propagation 指定事務的傳播行為。
timeout 指定超時時間。默認值為:-1。永不超時。
rollback-for 用於指定一個異常,當執行產生該異常時,事務回滾。產生其他異常,事務不回滾。沒有默認值,任何異常都回滾。
no-rollback-for 用於指定一個異常,當產生該異常時,事務不回滾,產生其他異常時,事務回
滾。沒有默認值,任何異常都回滾。

9.配置 AOP 切入點表達式

 <!-- AOP切入點表達式 -->
 <aop:config>
  <aop:pointcut expression="execution (* com.gql.service.UserServiceImp.*(..))" id="point" />
  <!-- 切入點表達式和事務的對應關系 -->
  <aop:advisor advice-ref="tx" pointcut-ref="point" />
 </aop:config>

10.配置切入點表達式和事務通知的對應關系

 <!-- AOP切入點表達式 -->
 <aop:config>
  <aop:pointcut expression="execution (* com.gql.service.UserServiceImp.*(..))" id="point" />
  <!-- 切入點表達式和事務的對應關系 -->
  <aop:advisor advice-ref="tx" pointcut-ref="point" />
 </aop:config>

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: