`
段箭*残箫
  • 浏览: 53706 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类

分层架构下的纯JDBC事务控制简单解决方案

阅读更多

对目前的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事务中把数据库连接绑定到线程,以保证在同一个线程下获得的都是同一个连接。这样就达到目的了。

如下数据库工具类:

view plaincopy to clipboardprint?
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.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.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);
  }
 }
}
 

如下业务层类:

view plaincopy to clipboardprint?
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();  
        }  
    }  

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();
  }
 }
}

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qjyong/archive/2010/04/08/5464835.aspx

分享到:
评论

相关推荐

    分层架构下的纯JDBC事务控制示例项目

    非常常用的JavaEE四层架构下的纯JDBC事务控制简单解决方案。Eclipse工程。详情参看:http://blog.csdn.net/qjyong/archive/2010/04/08/5464835.aspx

    数据治理概述及技术解决方案.pptx

    2. **技术实现架构**:系统采用分层架构,包括资源层、业务层、集成层、管理与控制层、表现层和客户层。技术组件包括JDBC、Hibernate、XML配置、日志管理、安全控制、任务/事务处理、分析引擎等,支持数据导入导出、...

    生产调度管理信息系统解决方案.doc

    "生产调度管理信息系统解决方案" 智能生产调度管理系统是基于生产计划的实时工艺信息和设备运行状态信息,提供包括计划执行与修正、资源合理利用、产量与质量统计分析、平稳工况的优化调度、异常工况的动态调度、...

    基于SSH2的Java EE轻量级解决方案的研究与实践

    SSH2的整合使用,使得Java EE应用的分层架构更加清晰,通常分为表现层(Struts 2)、业务逻辑层(Spring)、数据访问层(Hibernate)。这样的分层设计有利于团队协作,每个层次可以独立开发和测试,降低了复杂性。...

    WAS通用解决方案 中间件

    【中间件】是一种软件服务,它位于操作系统和应用程序...总的来说,WAS作为中间件解决方案,为电子商务平台提供了强大而灵活的基础,通过其丰富的功能和对企业级需求的支持,能够构建稳定、安全、高性能的Web应用系统。

    基于SQL-92和JDBC的SpaceOS数据库数据迁移的实现.pdf

    文章中设计的数据迁移模块采用了分层架构,包括表示层、元数据层、业务逻辑层和数据访问层。这种结构有助于模块化和解耦,提高代码的可维护性和可扩展性。 【数据类型映射】 在迁移过程中,不同的数据库系统可能...

    j2ee构建企业级应用解决方案

    本资料集围绕“J2EE构建企业级应用解决方案”这一主题,旨在帮助开发者理解并掌握在J2EE平台上开发复杂企业应用的关键技术。 1. **J2EE架构**:J2EE架构由多个层次组成,包括客户端层、Web层、业务逻辑层(EJB)和...

    Java EE 轻量级解决方案 — SSH 青岛东合信息技术有限公司 青岛海尔软件公司 著 教材源码 _ 第八章 Spring深入.

    【Java EE轻量级解决方案——SSH】是一种广泛应用于企业级应用开发的技术栈,它由三个主要部分组成:Spring、Struts和Hibernate。本章节重点讨论的是Spring框架的深入理解和应用。 Spring是Java EE平台的核心组件,...

    J2EE企业级项目开发-1期 09 Spring使用经验.doc

    1. **分层架构**:Spring 推荐采用 MVC(Model-View-Controller)架构,Action 层负责视图控制,Service 层处理业务逻辑,DAO 层专注数据访问。结构清晰,职责明确。 2. **依赖注入(DI)与组件扫描**:通过 @...

    spring介绍PPT

    Spring 框架简介 Spring 是一个开源的 Java 应用框架,由 Mark Eagle 贡献并维护,他是一位在Atlanta...Spring还提供了丰富的数据库组件支持,如数据访问工具和ORM解决方案,进一步增强了其在企业应用开发中的实用性。

    Spring核心技术文档

    它提供了一个分层架构,将模型、视图和控制器分离,提高代码的可重用性和可测试性。 8. **Spring Boot**:为了简化Spring应用程序的初始化和配置,Spring推出了Spring Boot。它通过默认配置和自动配置机制,使得...

    Spring 30道面试题和答案.docx

    它以其轻量级、松散耦合的特性著称,拥有一个分层架构,允许用户根据需求选择组件,同时也为J2EE应用提供了一体化的解决方案。Spring可以与其他框架如Struts、Hibernate、EJB等无缝集成,因此被称为“框架的框架”。...

    SSH架构简介.pdf

    总结起来,SSH架构结合了Spring的灵活控制反转和面向切面编程、Struts2的MVC设计模式和拦截器机制,以及Hibernate的对象关系映射能力,形成了一个全面、高效的Java Web开发解决方案。这个架构能够帮助开发者更专注于...

    spring4.0-released 开发包

    其次,Spring MVC是用于构建Web应用程序的模块,它提供了一种分层架构,使得控制器、视图、模型可以松耦合地工作。在4.0版本中,Spring MVC引入了更好的异步处理支持,增强了模板引擎集成,以及对Servlet 3.0 API的...

    java_SSH三大框架介绍

    Spring的事务管理抽象提供了一致的编程模型,无论底层使用何种事务技术,如JTA或JDBC事务。Spring还提供了一个轻量级的数据访问框架,使得开发者可以以面向对象的方式操作数据库,不必直接与JDBC打交道。同时,...

    java 一个根据配置文件对数据库进行增删改查的三层架构解决方法

    总结来说,本解决方案提供了一种基于配置文件的Java三层架构,用于对数据库进行增删改查操作。这种设计使系统更具有灵活性、可扩展性和可维护性,同时也简化了数据库环境的管理和变更。通过合理地划分各层职责,以及...

    Spring.docx

    Spring 是一个广泛应用于企业级 Java 开发的开源框架,它以其分层架构、全面的 JavaEE 解决方案和轻量级特性而受到开发者喜爱。Spring 的核心理念是控制反转(IoC)和面向切面编程(AOP),这两个概念有助于降低系统...

Global site tag (gtag.js) - Google Analytics