论坛首页 Java企业应用论坛

一个dao模型,带事务和异常处理,请指正!

浏览 3750 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-10-11   最后修改:2011-10-11
DAO

简介:
一个纯jdbc的dao模型,参考网上多篇相关技术文章,重点包括:
1.事务处理;
2.模板设计;
3.异常处理;
其中事务和异常方面一直也是争议比较大的地方,希望大家多指正,提出宝贵的意见。

首先是dao的结构描述:

首先是一些基础类,包括:

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  

 

 

 

 

 

 

 

 

   发表时间:2011-11-30  
说实话看了你这个DAO设计,写得不错,和我自己的想法大同小异,无非我就多了一个连接池的管理没有这个DBUtil,如果有新的需要可以在此基础上扩展
0 请登录后投票
   发表时间:2012-03-05  
很不错的dao实现
0 请登录后投票
   发表时间:2012-03-05  
看完了,提两个问题(可能是我没看到):
1、嵌套事务的支持能力(好像只看到单事务)
2、事务隔离级别设定(没看到)

加一条建议:
用AOP来实现事务,不用开发人员每次都得写execute
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics