分层架构下的纯JDBC事务控制简单解决方案【转】
http://blog.csdn.net/qjyong/article/details/5464835
对目前的JavaEE企业应用开发来说,基本都会采用分层的架构, 这样可以分散关注、松散耦合、逻辑复用、标准定义。例如,目前使用SSH组合时典型的四层架构:表示层、业务层、持久层和数据层;那么,在四层架构中,事务的控制应该放在哪一层呢?
如果使用Spring框架,它对事务做了很好的封装,通过它的AOP配置,可以灵活的配置在任何一层;但是在很多的需求和应用,直接使用JDBC事务控制还是有其优势的。所以,本文来讨论纯JDBC事务的控制问题。
其实,事务是以业务逻辑为基础的;一个完整的业务应该对应业务层里的一个方法;如果业务操作失败,则整个事务回滚;所以,事务控制是绝对应该放在业务层的;但是,持久层的设计应该遵循一个很重要的原则:持久层应该保证操作的原子性,就是说持久层里的每个方法都应该是不可以分割的。
例如针对一个部门和员工的CRUD操作。如果要删除某个部门,就应该在DeptDao中有一个删除部门的方法:
public class DeptDao {
public void deleteDept(int id) ; //删除指定ID的部门
}
在EmpDao中有一个删除指定部门下的所有员工的方法
public interface EmpDao{
public void deleteEmpByDeptId(int id); //删除指定部门下的所有员工
}
这样,就应该在业务层DeptService中的删除部门方法中组合这两个方法,即把它们放置在同一个事务中:
public class DeptService{
public void deleteDept(int id){
try{
//启动JDBC事务
//调用EmpDao中的deleteEmpByDeptId(id)方法
//调用DeptDao中的deleteDept(id)方法
//操作正常,提交事务
}catch(Exception e){
//异常,回滚事务
}
}
}
要让这两个Dao操作在同一个事务,最主要的一点就是:启动JDBC事务中使用的数据库连接和两个Dao操作方法里获得的数据库连接要是同一个连接。参照Spring的JDBC事务原理,可以使用ThreadLocal类, 在启动JDBC事务中把数据库连接绑定到线程,以保证在同一个线程下获得的都是同一个连接。这样就达到目的了。
如下数据库工具类:
- package com.tjitcast.common;
- import java.io.IOException;
- import java.sql.Connection;
- import java.sql.SQLException;
- import java.util.Properties;
- import javax.sql.DataSource;
- import com.mchange.v2.c3p0.DataSources;
- import com.tjitcast.dao.DaoException;
- /**
- * 数据库工具类
- * 可以根据classpath下配置文件jdbc.properties中配置的参数来获取数据库连接并绑定到当前线程上
- * 可以获取JDBC的事务管理器
- * @author qiujy
- * @version 0.9Beta
- */
- public class DbUtils {
- private static Properties prop = new Properties();
- /** 数据源 */
- private static DataSource ds = null;
- //用来把Connection绑定到当前线程上的变量
- private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
- static{
- try {
- prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties"));
- } catch (IOException e) {
- e.printStackTrace();
- System.out.println("在classpath下没有找到jdbc.properties文件");
- }
- //使用C3P0连接池技术
- try {
- Class.forName("com.mysql.jdbc.Driver");
- DataSource unpooled = DataSources.unpooledDataSource(
- prop.getProperty("url"),
- prop.getProperty("user"),
- prop.getProperty("password"));
- ds = DataSources.pooledDataSource(unpooled);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- private DbUtils(){}
- /**
- * 根据数据库的默认连接参数获取数据库的Connection对象,并绑定到当前线程上
- * @return 成功,返回Connection对象,否则返回null
- */
- public static synchronized Connection getConnection(){
- Connection conn = tl.get(); //先从当前线程上取出连接实例
- if(null == conn){ //如果当前线程上没有Connection的实例
- try {
- conn = ds.getConnection(); // 从连接池中取出一个连接实例
- tl.set(conn); //把它绑定到当前线程上
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return conn;
- }
- /**
- * 获取事务管理器
- * @return 事务管理实例
- */
- public static synchronized TransactionManager getTranManager(){
- return new TransactionManager(getConnection());
- }
- /**
- * 关闭数据库连接,并卸装线程绑定
- * @param conn 要关闭数据库连接实例
- * @throws DaoException
- */
- protected static void close(Connection conn) throws DaoException{
- if(conn != null){
- try {
- conn.close();
- } catch (SQLException e) {
- throw new DaoException("关闭连接时出现异常",e);
- } finally {
- tl.remove(); //卸装线程绑定
- }
- }
- }
- }
如下事务管理器类:
- package com.tjitcast.common;
- import java.sql.Connection;
- import java.sql.SQLException;
- import com.tjitcast.dao.DaoException;
- /**
- * 事务管理器
- * @author qiujy
- * @version 0.9Beta
- */
- public class TransactionManager {
- private Connection conn;
- protected TransactionManager(Connection conn) {
- this.conn = conn;
- }
- /** 开启事务 */
- public void beginTransaction() throws DaoException{
- try {
- conn.setAutoCommit(false); //把事务提交方式改为手工提交
- } catch (SQLException e) {
- throw new DaoException("开户事务时出现异常",e);
- }
- }
- /** 提交事务并关闭连接 */
- public void commitAndClose() throws DaoException{
- try {
- conn.commit(); //提交事务
- } catch (SQLException e) {
- throw new DaoException("提交事务时出现异常",e);
- }finally{
- DbUtils.close(conn);
- }
- }
- /** 回滚并关闭连接 */
- public void rollbackAndClose()throws DaoException{
- try {
- conn.rollback();
- } catch (SQLException e) {
- throw new DaoException("回滚事务时出现异常",e);
- }finally{
- DbUtils.close(conn);
- }
- }
- }
如下业务层类:
- package com.tjitcast.service;
- import java.util.List;
- import com.tjitcast.common.DbUtils;
- import com.tjitcast.common.TransactionManager;
- import com.tjitcast.dao.DaoException;
- import com.tjitcast.dao.DaoFactory;
- import com.tjitcast.dao.DeptDao;
- import com.tjitcast.dao.EmployeeDao;
- import com.tjitcast.entity.Dept;
- import com.tjitcast.entity.Employee;
- import com.tjitcast.entity.PageModel;
- /**
- * 业务层门面 --> 添加事务控制
- * @author qiujy
- */
- public class ServiceFacade {
- private DeptDao deptDao = DaoFactory.getInstance("deptDao", DeptDao.class);
- private EmployeeDao empDao = DaoFactory.getInstance("empDao", EmployeeDao.class);
- /**
- * 新增部门
- * @param dept
- */
- public void insertDept(Dept dept){
- TransactionManager tx = DbUtils.getTranManager();
- try{
- tx.beginTransaction();
- deptDao.insert(dept);
- tx.commitAndClose();
- }catch (DaoException e) {
- tx.rollbackAndClose();
- }
- }
- /**
- * 新增员工
- * @param emp 员工
- */
- public void insertEmp(Employee emp){
- TransactionManager tx = DbUtils.getTranManager();
- try{
- tx.beginTransaction();
- empDao.insert(emp);
- tx.commitAndClose();
- }catch (DaoException e) {
- tx.rollbackAndClose();
- }
- }
- /**
- * 获取所有部门的列表
- * @return 部门列表
- */
- public List<Dept> getDeptList(){
- List<Dept> list = null;
- TransactionManager tx = DbUtils.getTranManager();
- try{
- tx.beginTransaction();
- list = deptDao.getDeptList();
- tx.commitAndClose();
- }catch (DaoException e) {
- e.printStackTrace();
- tx.rollbackAndClose();
- }
- return list;
- }
- /**
- * 获取指定部门下的员工分页列表
- * @param deptId
- * @param pageNo
- * @param pageSize
- * @return 符合条件的PageModel
- */
- public PageModel<Employee> getEmpListByDeptId(int deptId, int pageNo, int pageSize){
- PageModel<Employee> pm = null;
- TransactionManager tx = DbUtils.getTranManager();
- try{
- tx.beginTransaction();
- pm = empDao.getEmpListByDeptId(deptId, pageNo, pageSize);
- tx.commitAndClose();
- }catch (DaoException e) {
- tx.rollbackAndClose();
- }
- return pm;
- }
- /**
- * 删除指定ID的部门
- * @param id 部门ID
- */
- public void deleteDept(int id){
- TransactionManager tx = DbUtils.getTranManager();
- try{
- tx.beginTransaction();
- empDao.deleteByDeptId(id); //先删除指定ID部门下的所有员工
- deptDao.delete(id); //再删除该部门
- tx.commitAndClose();
- }catch (DaoException e) {
- tx.rollbackAndClose();
- }
- }
- }
具体的示例代码结构如下(Eclipse工程):

分层架构下的纯JDBC事务控制简单解决方案【转】的更多相关文章
- JDBC事务控制管理(转载)
JDBC事务控制管理 转载于 2018年01月26日 15:46:11 1.事务 (1)事务的概念 事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功. 例如:A——B转帐, ...
- JDBC 事务控制
一.简介: 前面一遍提到了jdbc事务相关的概念.从中了解到事务应具有ACID特性.所以对于javaweb开发来说,某一个service层的方法,应该是一个事务,应该是具有原子性的.特别是当一个ser ...
- JDBC事务控制管理
1.事务 (1)事务的概念 事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功. 例如:A——B转帐,对应于如下两条sql语句 update account set mone ...
- JDBC事务控制
概念 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并 ...
- JDBC事务的简单使用
在实际功能当中,经常会碰到同时对一组数据进行增加和减少,最常见的就是交易功能. 事务内执行的语句,要么都成功,要么都失败,如果有一句没执行成功,整个事务都不会提交的. import java.sql. ...
- 事务和JDBC事务隔离级别
与事务相关的理论 mysql事物隔离级别:http://mj4d.iteye.com/blog/1744276 事务(Transaction): 是并发控制的单元,是用户定义的一个操作序列.这些操作要 ...
- jdbc事务、连接池概念、c3p0、Driud、JDBC Template、DBUtils
JDBC 事务控制 什么是事务:一个包含多个步骤或者业务操作.如果这个业务或者多个步骤被事务管理,则这多个步骤要么同时成功,要么回滚(多个步骤同时执行失败),这多个步骤是一个整体,不可分割的. 操作: ...
- ActiveX数据对象之事务控制在VB和DELPHI中的应用
本文发表在中国人民解放军"信息工程大学"学报 2001年第3期. ActiveX数据对象之事务控制在VB和DELPHI中的应用 ...
- 一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.分布式架构下,Session共享有什么方案 2.简述你对RPC.RMI的理解 3.分布式id生成方案 4.分布式锁解决 ...
随机推荐
- 设备模型的基础---kobject,kset
设备模型的基础是kobject,kset,kobj_type.kobject本身并没有什么意义,真正有用的地方在于嵌入了kobject的结构体(对象),kobject可以看成是一个最小单元,sysfs ...
- SQL数据库查询练习题
一. 设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Teacher).四个表的结构分别如表1-1的表(一)~表( ...
- Java中List的排序和List的MAp
这里是一个类中类去实现条件优先排序的问题 package com.sun; import java.util.ArrayList; import java.util.Arrays; import ja ...
- DataUml Design 教程7 - 数据库生成模型
DataUml Design支持数据库生成模型,并支持外键关系,能够根据外键自动生成类与类之间的关系. 目前DataUML Design支持MS Server.MY SQL.Oracle和Access ...
- hibernate的helloworld实现
首先要新建一个 web project,然后新建一个lib的文件夹并导入相应的jar包 hibernate开发步骤: 1.创建hibernate配置文件 2.创建持久化类 3.创建对象关系映射文件 如 ...
- [开源]C#中开源软件大汇总(外国的)
一.博客类项目 1.SubText 项目介绍:Subtext 是一个个人博客发布平台,详细的介绍请进SubText 项目分类:博客 项目license:BSD License 项目主页:http:// ...
- Windows 下tomcat安装及将多个tomcat注册为Windows服务
一.应用场景 虽然Windows在当下已经不再是我们作为服务器操作系统平台的首选,但是还是有一些开发商或者项目整体需求的限制必须运行在Windows系统平台之下.为了避免多个应用部署在同一个tomca ...
- python 动态语言 __slots__
python 是动态语言,就是说可以动态的创建属性, 别的语言不行,再创建类的时候已经规定好了 使用__slots__,注意要用tuple定义同意绑定的属性名称,仅对当前类起作用,对继承的子类是不起作 ...
- What is /dev/null 2>&1?
>> /dev/null redirects standard output (stdout) to /dev/null, which discards it. (The >> ...
- 怎么用ChemDraw Pro绘制不定域共轭环
ChemDraw Pro 14作为一款非常受欢迎的化学绘图软件,不论是化学分子结构.轨道,还是符号.箭头等图形都可以用它轻松的绘制出来,而且在其工具栏中,集成了10种环工具,可以对不同种类.不同尺寸的 ...