锁定老帖子 主题:一个dao模型,带事务和异常处理,请指正!
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-10-11
最后修改:2011-10-11
简介: 首先是一些基础类,包括: dbutil: 数据库操作基础类(获取数据库连接、获取事务管理器等) transactionTemplate: 事务处理模板类 transactionManager: 事务管理器 transactionCallback: 事务处理回调方法(返回结果) transactionCallbackWithoutResult: 事务处理回调方法(不返回结果) 详细类容请参考源码:
DBUtil:
package com.bts.db; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import org.apache.log4j.Logger; import com.bts.exception.dao.DaoException; import com.bts.util.LogUtil; import com.bts.util.PropertiesRW; /** * @author huangfox * @serial 数据库连接池 采用dbcp组件。 <br> * */ public class DBUtil { private static Logger logger = Logger.getLogger(DBUtil.class); private static BasicDataSource ds = null; private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); static { try { PropertiesRW proRW = new PropertiesRW("src/dbcpParamter.properties"); Properties conf = proRW.getProperties(); ds = (BasicDataSource) BasicDataSourceFactory .createDataSource(conf); } catch (Exception e) { logger.error(LogUtil.logInfo("初始化数据库连接池时发生异常!", e)); } } /** * 根据数据库的默认连接参数获取数据库的Connection对象,并绑定到当前线程上 * * @return 成功,返回Connection对象,否则返回null * @throws DaoException */ public static synchronized Connection getConnection() throws DaoException { // 先从当前线程上取出连接实例 Connection conn = tl.get(); // 如果当前线程上没有Connection的实例 if (null == conn) { try { // 从连接池中取出一个连接实例 conn = ds.getConnection(); // 把它绑定到当前线程上 tl.set(conn); } catch (SQLException e) { throw new DaoException("获取数据库连接时发生异常!", e); } } return conn; } /** * 获取事务管理器 * * @return 事务管理实例 * @throws DaoException */ public static synchronized TransactionManager getTranManager() throws DaoException { 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(); } } } /** * 关闭ResultSet、Statement。 * * @param rs * @param stat * @throws DaoException */ public static void free(ResultSet rs, Statement stat) throws DaoException { try { if (rs != null) rs.close(); if (stat != null) stat.close(); } catch (SQLException e) { throw new DaoException("关闭ResultSet/Statement时出现异常!", e); } } } TransactionCallback
package com.bts.db; import com.bts.exception.dao.DaoException; /** * @author huangfox * @serial 事务回调接口 */ public interface TransactionCallback<T> { /** * 要在事务中回调执行的方法 * * @return 所指定类型的数据 * @throws DaoException */ T doInTransaction() throws DaoException; } TransactionCallbackWithoutResult:
package com.bts.db; import com.bts.exception.dao.DaoException; /** * @author huangfox * @serial 无返回值的事务回调接口 */ public interface TransactionCallbackWithoutResult { /** * 要在事务中回调执行的方法 * @throws DaoException * */ public void doInTransaction() throws DaoException; } TransactionManager:
package com.bts.db; import java.sql.Connection; import java.sql.SQLException; import com.bts.exception.dao.DaoException; /** * @author huangfox * @serial 事务管理器 */ public class TransactionManager { private Connection conn; protected TransactionManager(Connection conn) { this.conn = conn; } /** * 开启事务 * * @throws DaoException */ public void beginTransaction() throws DaoException { try { // 把事务提交方式改为手工提交 conn.setAutoCommit(false); } catch (SQLException e) { throw new DaoException("开始事务时出现异常", e); } } /** * 提交事务并关闭连接 * * @throws DaoException */ public void commitAndClose() throws DaoException { try { conn.commit(); } catch (SQLException e) { DBUtil.close(conn); throw new DaoException("提交事务时出现异常", e); } finally { } } /** * 回滚并关闭连接 * * @throws DaoException */ public void rollbackAndClose() throws DaoException { try { conn.rollback(); } catch (SQLException e) { DBUtil.close(conn); throw new DaoException("回滚事务时出现异常", e); } finally { } } } TransactionTemplate:
package com.bts.db; import org.apache.log4j.Logger; import com.bts.exception.dao.DaoException; import com.bts.util.LogUtil; /** * @author huangfox * @serial 事务执行模板,可以在service中避免事务的倾入。 */ public class TransactionTemplate { private static Logger logger = Logger.getLogger(TransactionTemplate.class); /** * 在事务里执行回调接口实现类中有返回值的方法 * * @param <T> * 返回值类型 * @param callback * 回调接口 * @return 指定类型的返回值 * @throws DaoException * 数据访问异常 */ public static <T> T execute(TransactionCallback<T> callback) { T result = null; TransactionManager tx = null; try { tx = DBUtil.getTranManager(); // 开启事务 tx.beginTransaction(); // 执行回调方法 result = callback.doInTransaction(); // 提交事务并关闭 tx.commitAndClose(); } catch (DaoException e) { logger.error(LogUtil.logInfo(e)); } finally { try { tx.rollbackAndClose(); } catch (DaoException e) { logger.error(LogUtil.logInfo(e)); } } return result; } /** * 在事务里执行回调接口实现类中没有返回值的方法 * * @param callback * 回调接口 * @throws DaoException * 数据访问异常 */ public static void execute(TransactionCallbackWithoutResult callback) { TransactionManager tx = null; try { tx = DBUtil.getTranManager(); tx.beginTransaction(); callback.doInTransaction(); tx.commitAndClose(); } catch (DaoException e) { logger.error(LogUtil.logInfo(e)); } finally { try { tx.rollbackAndClose(); } catch (DaoException e) { logger.error(LogUtil.logInfo(e)); } } } }
---------------------------------------------------------------
接下来就是dao方面的设计 定义一个接口dao,规范出共有的数据操作。 具体业务也定义一个接口***dao,继承自接口dao,该***dao主要可以定义一些特殊的方法。(该接口的定义需要结合实际情况判断有无必要)! 然后是一个常用的daoTemplate,定义通用的数据库操作。
Dao接口:
package com.bts.dao; import java.util.List; import com.bts.exception.dao.DaoException; /** * @author huangfox * @serial dao接口,定义各个业务对象数据库访问接口的公用方法。 * @param <T> */ public interface Dao<T> { /** * 根据查询条件获取具体某条数据 * * @param args * @return * @throws DaoException */ public T select(T args) throws DaoException; /** * 根据查询条件获取所有数据 * * @param args * @return * @throws DaoException */ public List<T> query(T args) throws DaoException; /** * 根据查询条件获取结果总数。 * * @param args * @return * @throws DaoException */ public int getCount(T args) throws DaoException; /** * 插入某一条数据 * * @param one * @throws DaoException */ public void insert(T one) throws DaoException; /** * 插入多条数据 * * @param multi * @throws DaoException */ public void insert(List<T> multi) throws DaoException; /** * 更新某一条数据 * * @param one * @throws DaoException */ public void update(T one) throws DaoException; /** * 更新多条数据 * * @param multi */ public void update(List<T> multi) throws DaoException; /** * 删除某一条数据 * * @param one * @throws DaoException */ public void delete(T one) throws DaoException; /** * 删除多条数据 * * @param multi */ public void delete(List<T> multi) throws DaoException; }
DaoTemplate:
package com.bts.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import com.bts.db.DBUtil; import com.bts.exception.dao.DaoException; /** * @author huangfox * @serial <br> * 模板方法,主要抽取dao中jdbc操作的公用方法。 <br> * 另外定义相应的抽象方法,强制子类实现,主要功能包括resultSet对业务对象的转换、查询条件构造等。 * @param <T> */ public abstract class DaoTemplate<T> { /** * 获取符合查询条件的某一条数据。 * * @param sql * @param args * 查询条件 * @return * @throws DaoException */ public T findTemplate(String sql, Object[] args) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); rs = ps.executeQuery(); T obj = null; if (rs.next()) { obj = rs2obj(rs); } return obj; } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { DBUtil.free(rs, ps); } } /** * 获得符合查询条件的结果记录总数。 * * @param sql * @param args * 查询条件 * @return * @throws DaoException */ public int getCountTemplate(String sql, Object[] args) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); rs = ps.executeQuery(); int count = 0; if (rs.next()) { count = rs.getInt(1); } return count; } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { DBUtil.free(rs, ps); } } /** * 获取符合条件的所有数据 * * @param sql * @param args * 查询参数 * @return * @throws DaoException */ public List<T> QueryTemplate(String sql, Object[] args) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<T> results = new ArrayList<T>(); try { conn = DBUtil.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); rs = ps.executeQuery(); T obj = null; while (rs.next()) { obj = rs2obj(rs); results.add(obj); } return results; } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { DBUtil.free(rs, ps); } } /** * 更新操作 * * @param sql * @param args * @param isGeneralKey * @throws DaoException */ public void updateTemplate(String sql, Object[] args, boolean isGeneralKey) throws DaoException { Connection conn = null; PreparedStatement ps = null; try { conn = DBUtil.getConnection(); ps = (isGeneralKey ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn .prepareStatement(sql)); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); ps.executeUpdate(); } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { DBUtil.free(null, ps); } } /** * 批量更新操作 * * @param sql * @param args * @param isGeneralKey * @throws DaoException */ public void updateMultiTemplate(String sql, List<Object[]> args, boolean isGeneralKey) throws DaoException { Connection conn = null; PreparedStatement ps = null; try { conn = DBUtil.getConnection(); ps = (isGeneralKey ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn .prepareStatement(sql)); for (int i = 0; i < args.size(); i++) { for (int j = 0; j < args.get(i).length; j++) { ps.setObject(j + 1, args.get(i)[j]); } // ps.addBatch(); } ps.executeBatch(); } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { DBUtil.free(null, ps); } } /** * 准备查询条件。 * * @param sql * @param args * 查询条件 * @return */ public abstract String prepareQuery(String sql, T args); /** * 用于resultSet与具体业务对象转化的方法。 * * @param rs * @return * @throws SQLException */ public abstract T rs2obj(ResultSet rs) throws SQLException; }
TaskDao:(改接口有待讨论)
package com.bts.dao; import com.bts.bean.Task; /** * @author huangfox * * @serial 具体业务对象(Task)的数据访问接口, 继承接口DAO的基础方法,<br> * 并且可以定义在此定义特殊的方法。 * */ public interface TaskDao extends Dao<Task> { // 特殊方法 } TaskDaoImpl:
package com.bts.dao.impl; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.bts.bean.Task; import com.bts.dao.DaoTemplate; import com.bts.dao.TaskDao; import com.bts.exception.dao.DaoException; /** * @author huangfox * @serial * */ public class TaskDaoImpl extends DaoTemplate<Task> implements TaskDao { @Override public Task select(Task args) throws DaoException { String sql = " select * from FeeInfoTasks where ApplicationNumber = ? "; Object[] params = new Object[] { args.getAppNum() }; Task result = new Task(); result = findTemplate(sql, params); return result; } @Override public List<Task> query(Task args) throws DaoException { String sql = " select * from FeeInfoTasks where 1 = 1 "; sql = prepareQuery(sql, args); Object[] params = new Object[] {}; List<Task> result = new ArrayList<Task>(); result = QueryTemplate(sql, params); return result; } @Override public int getCount(Task args) throws DaoException { String sql = " select count(*) from FeeInfoTasks where 1 = 1 "; sql = prepareQuery(sql, args); Object[] params = new Object[] {}; int count = 0; count = getCountTemplate(sql, params); return count; } @Override public void insert(Task one) throws DaoException { String sql = " insert into FeeInfoTasks " + "(ApplicationNumber,NoticeDate,PRI,Status,UpdateTime,FeeCount) values " + "(?,?,?,?,?,?) "; Object[] params = new Object[] { one.getAppNum(), one.getNoticeDate(), one.getPrimary(), one.getStatus(), one.getUpdateTime(), one.getFeeCount() }; updateTemplate(sql, params, false); } @Override public void update(Task one) throws DaoException { String sql = " update FeeInfoTasks set " + "NoticeDate = ? , PRI = ? , " + "Status = ? , UpdateTime = ? , FeeCount = ? " + "where ApplicationNumber =? "; Object[] params = new Object[] { one.getNoticeDate(), one.getPrimary(), one.getStatus(), one.getUpdateTime(), one.getFeeCount(), one.getAppNum() }; updateTemplate(sql, params, false); } @Override public void delete(Task one) throws DaoException { String sql = " delete from FeeInfoTasks where ApplicationNumber = ? "; Object[] params = new Object[] { one.getAppNum() }; updateTemplate(sql, params, false); } @Override public void insert(List<Task> multi) throws DaoException { String sql = " insert into FeeInfoTasks " + "(ApplicationNumber,NoticeDate,PRI,Status,UpdateTime,FeeCount) values " + "(?,?,?,?,?,?) "; List<Object[]> paramList = new ArrayList<Object[]>(); for (int i = 0; i < multi.size(); i++) { Task one = multi.get(i); Object[] params = new Object[] { one.getAppNum(), one.getNoticeDate(), one.getPrimary(), one.getStatus(), one.getUpdateTime(), one.getFeeCount() }; paramList.add(params); } updateMultiTemplate(sql, paramList, false); } @Override public void update(List<Task> multi) { // TODO Auto-generated method stub } @Override public void delete(List<Task> multi) { // TODO Auto-generated method stub } @Override public Task rs2obj(ResultSet rs) throws SQLException { Task task = new Task(); if (rs != null) { task.setAppNum(rs.getString("ApplicationNumber")); task.setNoticeDate(rs.getString("NoticeDate")); task.setPrimary(rs.getInt("PRI")); task.setStatus(rs.getInt("Status")); task.setUpdateTime(rs.getString("UpdateTime")); task.setFeeCount(rs.getInt("FeeCount")); } return task; } @Override public String prepareQuery(String sql, Task args) { if (args != null) { if (args.getAppNum() != null) sql += " and ApplicationNumber = " + args.getAppNum(); if (args.getNoticeDate() != null) sql += " and NoticeDate = " + args.getNoticeDate(); sql += " and PRI = " + args.getPrimary(); sql += " and Status = " + args.getStatus(); if (args.getUpdateTime() != null) sql += " and UpdateTime = " + args.getUpdateTime(); sql += " and FeeCount = " + args.getFeeCount(); } return sql; } } 注意:以上仅为部分实现!
---------------------------------------------------------
到这里,我们就要关心事务处理方面的问题了。 我将事务处理放到了service层,采用的是回调的方式。 参考:http://blog.csdn.net/qjyong/article/details/5513638
TaskService:
package com.bts.service; import java.util.List; import com.bts.bean.Task; import com.bts.dao.TaskDao; import com.bts.dao.impl.TaskDaoImpl; import com.bts.db.TransactionCallback; import com.bts.db.TransactionCallbackWithoutResult; import com.bts.db.TransactionTemplate; import com.bts.exception.dao.DaoException; /** * @author huangfox * */ public class TaskService { public TaskDao dao = null; public TaskService() { super(); this.dao = new TaskDaoImpl(); } /** * 通过applicationNumber获取Task。 * * @param args * @return * @throws DaoException */ public Task getTaskByApplicationNumber(final Task args) { return TransactionTemplate.execute(new TransactionCallback<Task>() { @Override public Task doInTransaction() throws DaoException { return dao.select(args); } }); } /** * 获取所有符合条件的Task。 * * @param args * @return * @throws DaoException */ public List<Task> getTasks(final Task args) { return TransactionTemplate .execute(new TransactionCallback<List<Task>>() { @Override public List<Task> doInTransaction() throws DaoException { return dao.query(args); } }); } /** * 获取所有符合条件的Task的总量。 * * @param args * @return * @throws DaoException */ public int getTasksCount(final Task args) { return TransactionTemplate.execute(new TransactionCallback<Integer>() { @Override public Integer doInTransaction() throws DaoException { return dao.getCount(args); } }); } /** * 添加一个任务。 * * @param one * @throws DaoException */ public void addTask(final Task one) { TransactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransaction() throws DaoException { dao.insert(one); } }); } /** * 添加多个任务。 * * @param tasks */ public void addTaskMutil(final List<Task> tasks) { TransactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransaction() throws DaoException { dao.insert(tasks); } }); } /** * 根据申请号(ApplicationNumber)修改一个task。 * * @param one * @throws DaoException */ public void modifyTask(final Task one) { TransactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransaction() throws DaoException { dao.update(one); } }); } /** * 根据申请号(ApplicationNumber)删除一个Task。 * * @param one * @throws DaoException */ public void deleteTaskByAppNum(final Task one) { TransactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransaction() throws DaoException { dao.delete(one); } }); } }
--------------------------------------------------------------------- 如果哪位超级有耐心的看到了着,请你参与讨论这个dao模型中的不足,或者说说你项目中dao是怎么运用的! 重点可以关注: 事务处理 异常处理 设计模式 其他 :P
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-11-30
说实话看了你这个DAO设计,写得不错,和我自己的想法大同小异,无非我就多了一个连接池的管理没有这个DBUtil,如果有新的需要可以在此基础上扩展
|
|
返回顶楼 | |
发表时间:2012-03-05
很不错的dao实现
|
|
返回顶楼 | |
发表时间:2012-03-05
看完了,提两个问题(可能是我没看到):
1、嵌套事务的支持能力(好像只看到单事务) 2、事务隔离级别设定(没看到) 加一条建议: 用AOP来实现事务,不用开发人员每次都得写execute |
|
返回顶楼 | |
浏览 3750 次