`
kanny87929
  • 浏览: 17518 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

(模板方法的运用)持久层操作的java代码

阅读更多

2008年刚从学校毕业就应聘到了一家外包小公司工作
对加拿大的客户开发一些web项目
公司里算我就2个人是做java的
于是我们变成了一个人身兼数个项目的程序员
经理只给我们客户的需求
然后数据库设计、编码等事你一个人搞定。。。

我当时刚出来对java的理解还没有那么深,没有商业项目的任何经验就让我搞着搞那。
当时连数据库连接的操作我都很苦恼,是用简单的jdbc还是hibernate呢,
最后为了方便而达到目的我选用了前者。赶项目的效率还是很重要的。

我给出当时自己写的操作数据库的代码
这家公司大多都是.net的程序所以用的数据库也为sql server 2005
所以不知道这样写是不是会有很多问题,因为我总觉得有问题。
3年后虽然已经离开公司但再回头看这些代码,我还是觉得有问题,所以必须发出来大家审视一下。

这些代码是2008年4月刚出道时自己写的。当时正在读老师推荐给我的java设计模式,看到了template这个模式,于是在工作中突然想到可以把这个模式应用在操作数据库的代码上
于是就产生了以下代码。




第一个是操作数据库方法的抽象接口,
其实这个接口也很简单,定义了那么几个方法,说白了就是操作数据库的。
为什么要写成泛型的接口,为了就是后面大家的业务有针对性,一个实体一个业务功能类。


package com.yd.idao;

import java.util.List;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.yd.support.JDataSet;

/**
 * 一个定义了所有我所需要的数据库操作的方法接口,
 * 为什么定义为抽象,我自己都搞不清楚,
 * 这里定义了泛型,这个很关键,你会看到泛型在这里的使用
 * @author kanny
 *
 * @param <T>
 */
public abstract interface ISqlHelper<T> {

	/**
	 * 执行sql语句,大多为单句插入语句
	 * @param sql	单句的sql语句
	 * @param params	插入的参数
	 * @param only		但为true时,sql语句为查询数量的查询语句
	 * @return
	 * @throws SQLException
	 */
	public boolean execute(String sql, Object[] params, boolean only) throws SQLException;

	/**
	 * 执行sql的批处理
	 * @param sqlBatch	多条sql语句
	 * @return
	 * @throws SQLException
	 */
	public boolean executeBatch(String[] sqlBatch) throws SQLException;

	/**
	 * 执行存储过程
	 * @param procName	存储过程名称
	 * @param params	存储过程说需要的参数
	 * @return
	 * @throws SQLException
	 */
	public boolean executeCall(String procName, Object[] params) throws SQLException;

	/**
	 * 查询一行数据封装成java的实体
	 * @param sql	sql语句
	 * @param params	sql条件参数
	 * @param viewName	视图名字,在查询多表关联的数据时用于区分
	 * @param executeCall	是否是存储过程,如果为true,第一个sql的参数为存储过程名称
	 * @return
	 * @throws SQLException
	 */
	public T find(String sql, Object[] params, String viewName, boolean executeCall) throws SQLException;

	/**
	 * 查询多行数据封装成java的实体加入一个List里
	 * @param sql	sql语句
	 * @param params	sql条件参数
	 * @param viewName	视图名字,在查询多表关联的数据时用于区分,循环封装实体比单一的石头封装要复杂
	 * @param executeCall	是否是存储过程,如果为true,第一个sql的参数为存储过程名称
	 * @return
	 * @throws SQLException
	 */
	public List<T> findList(String sql, Object[] params, String viewName, boolean executeCall) throws SQLException;

	/**
	 * 为了方便操作,我还特意写定义了这个返回ResultSet的方法,便于直接操作
	 * @param sql
	 * @param params
	 * @param executeCall
	 * @return
	 * @throws SQLException
	 */
	public ResultSet returnResultSet(String sql, Object[] params, boolean executeCall) throws SQLException;
	
	/**
	 * 我的底层分页方法,我会给出具体代码,但这里用的只是sql server 2008的数据库分页
	 * @param sql	
	 * @param orderby	排序列
	 * @param currentPage	当前页
	 * @param pageSize	每页多少行
	 * @return
	 * @throws SQLException
	 */
	public List<T> findListAsPager(String sql, String orderby, int currentPage, int pageSize) throws SQLException;

	/**
	 * 后来为了方便操作,想朋友要来了这个JDataSet类,类似.net的DataTable的作用
	 * @param sql
	 * @param params
	 * @param fillColumnNames	是否填充类名,请看方法代码
	 * @param executeCall
	 * @return
	 */
	public JDataSet getJDataSet(String sql, Object[] params, boolean fillColumnNames, boolean executeCall);
	
	/**
	 * 由于有了JDataSet这个类,于是我有写了调用这个类的分页方法
	 * @param sql
	 * @param orderby
	 * @param currentPage
	 * @param pageSize
	 * @return
	 * @throws SQLException
	 */
	public JDataSet getJDataSetAsPager(String sql, String orderby, int currentPage, int pageSize) throws SQLException;
	
	/**
	 * 为了方便起见,我多写了一个直接传入ResultSet而封装JDataSet的多余方法
	 * @param rs
	 * @param fillColumnNames
	 * @return
	 * @throws SQLException
	 */
	public JDataSet loadJDataSet(ResultSet rs, boolean fillColumnNames) throws SQLException;
	
	/**
	 * 得到查询数据的行数
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	public int getRowCount(String sql) throws SQLException;
	
	/**
	 * 请看源码
	 * @param rs
	 * @param column
	 * @return
	 * @throws SQLException
	 */
	public String changeFont(ResultSet rs, String column) throws SQLException;
	
	/**
	 * 得到连接
	 * @return
	 * @throws SQLException
	 */
	public Connection returnConn() throws SQLException; 
	
	/**
	 * 清楚所有数据库操作对象
	 * @throws SQLException
	 */
	public void clearAllsql() throws SQLException; 

}




第2个类是实现这个抽象接口的抽象模版方法类
这个类最为关键,它肯定是实现了ISqlHepler.java里面的所有的方法。

其中:

protected abstract T loadDataBean(ResultSet rs, String viewName) throws SQLException;

protected abstract T loadDataBeanSelf(ResultSet rs) throws SQLException;

这2个方法是SqlHelper.java里留出来了,就是为了大家可以自己封装实体javabean来用

package com.yd.dao;

import java.sql.*;
import java.util.*;

import com.yd.db.DBConnPoolMgr;
import com.yd.idao.ISqlHelper;
import com.yd.support.JDataSet;

public abstract class SqlHelper<T> implements ISqlHelper<T> {

	protected java.sql.Connection conn = null;

	protected java.sql.PreparedStatement pst = null;

	protected java.sql.Statement st = null;

	protected java.sql.CallableStatement cs = null;

	protected java.sql.ResultSet rs = null;

	protected java.sql.ResultSetMetaData rm = null;
	
	public Connection returnConn() throws SQLException {

                  //DBConnPoolMgr是自己写的一个简单连接池类,用来得到连接,我后面会给出这个类的代码
		return (conn = DBConnPoolMgr.getInctence().getConnect());
	}
	
	private PreparedStatement returnPst(String sql, Object[] params) throws SQLException {

		if (conn == null || conn.isClosed()) conn = returnConn();
		pst = conn.prepareStatement(sql);
		if (params != null)
			for (int i = 0; i < params.length; i++)
				pst.setObject(i + 1, params[i]);
		return pst;
		
	}

	protected CallableStatement returnCs(String procName, Object[] params) throws SQLException {

		if (conn == null || conn.isClosed()) conn = returnConn();
		String call = "";
		if (params != null) {
			call = "{call " + procName + "(";
			for (int c = 0; c < params.length - 1; c++)
				call += "?,";
			call += "?)}";
		} else
			call = "{call " + procName + "()}";
		cs = conn.prepareCall(call);
		if (params != null)
			for (int i = 0; i < params.length; i++)
				cs.setObject(i + 1, params[i]);
		return cs;
		
	}

	public void clearAllsql() {
		try 
		{ 
			if (rs != null) rs.close();
			if (cs != null) cs.close();
			if (st != null) st.close();
			if (pst != null) pst.close();
			if (conn != null) {
				DBConnPoolMgr.getInctence().returnConnect(conn);
			}
			rs = null;
			cs = null;
			st = null;
			pst = null;
		} 
		catch (SQLException ex) { ex.printStackTrace(); }
	}

	public boolean execute(String sql, Object[] params, boolean only) {
		
		boolean bVal = false;
		try 
		{
			if (only) {
				rs = returnPst(sql, params).executeQuery();
				while (rs.next()) bVal = true;
			} else {
				returnPst(sql, params).executeUpdate();
				bVal = true;
			}
		} 
		catch (SQLException ex) { ex.printStackTrace(); } 
		finally { clearAllsql(); }
		return bVal;
	}

	public boolean executeBatch(String[] sqlBatch) {
		
		boolean bVal = false;
		try 
		{
			conn = returnConn();
			st = conn.createStatement();
			boolean autoCommit = conn.getAutoCommit();

			for (int i = 0; i < sqlBatch.length; i++) {
				if (sqlBatch[i] != null && !sqlBatch[i].equals(""))
					st.addBatch(sqlBatch[i] + ";");
			}
			conn.setAutoCommit(false);
			st.executeBatch();
			conn.commit();
			conn.setAutoCommit(autoCommit);
			bVal = true;
		} 
		catch (SQLException ex) {
			try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); }
			ex.printStackTrace();
		} finally { clearAllsql(); }
		return bVal;
	}

	public boolean executeCall(String procName, Object[] params) {
		
		boolean bVal = false;
		try 
		{
			returnCs(procName, params).executeUpdate();
			bVal = true;
		} 
		catch (Exception ex) { ex.printStackTrace(); } 
		finally { clearAllsql(); }
		return bVal;
	}

	public T find(String sql, Object[] params, String viewName, boolean executeCall) {
		
		T t = null;
		try 
		{
			if (executeCall) rs = returnCs(sql, params).executeQuery();
			else rs = returnPst(sql, params).executeQuery();
			t = loadResultSet(rs, viewName);
		} 
		catch (Exception ex) { ex.printStackTrace(); } 
		finally { clearAllsql(); }
		return t;
	}

	public List<T> findList(String sql, Object[] params, String viewName, boolean executeCall) {
		
		List<T> lt = null;
		try 
		{
			if (executeCall) rs = returnCs(sql, params).executeQuery();
			else rs = returnPst(sql, params).executeQuery();
			lt = loadList(rs, viewName);
		} 
		catch (Exception ex) { ex.printStackTrace(); } 
		finally { clearAllsql(); }
		return lt;
	}

	public ResultSet returnResultSet(String sql, Object[] params, boolean executeCall) {
		try 
		{
			if (executeCall) rs = returnCs(sql, params).executeQuery();
			else rs = returnPst(sql, params).executeQuery();
		} 
		catch (Exception ex) { ex.printStackTrace(); }
		return rs;
	}

	private T loadResultSet(ResultSet rs, String viewName) throws SQLException {
		
		T t = null;
		if (rs != null) while (rs.next()) t = loadDataBean(rs, viewName);
		return t;
	}

	private List<T> loadList(ResultSet rs, String viewName) throws SQLException {
		
		List<T> tlist = new ArrayList<T>();
		if (rs != null) 
			while (rs.next()) 
				tlist.add(loadDataBean(rs, viewName));
		return tlist;
	}

	public String changeFont(ResultSet rs, String column) throws SQLException {
		return rs.getString(column) == null ? "" : rs.getString(column);
	}

	public int returnColumnCount(ResultSet rs) throws SQLException {
		return rs.getMetaData().getColumnCount();
	}

         //两个非常关键的模版方法,继承此类的操作类都要实现这2个方法,我到时候会给出操作类
	protected abstract T loadDataBean(ResultSet rs, String viewName) throws SQLException;

	protected abstract T loadDataBeanSelf(ResultSet rs) throws SQLException;

	public List<T> findListAsPager(String sql, String orderby, int currentPage, int pageSize) {
		
		List<T> lt = null;
		try 
		{
			String strVal = strPager(sql, orderby, currentPage, pageSize);
			rs = returnPst(strVal, null).executeQuery();
			lt = loadList(rs, "");
		} 
		catch (SQLException ex) { ex.printStackTrace(); } 
		finally { clearAllsql(); }
		return lt;
	}

         //因为用的sql server 2008所以只写了这个数据库的分页
	private String strPager(String sql, String orderby, int currentPage, int pageSize) {
		
		int start = 1;
		if (currentPage > 1) start = (currentPage - 1) * pageSize + 1;
		int end = start + pageSize - 1;
		
		String sqlColumn = "*";
		String sqlDo = "";
		if(sql.indexOf("@#") != -1) {
			String []sqlArr = sql.split("@#");
			sqlColumn = sqlArr[0];
			sqlDo = sqlArr[1];
		} else {
			sqlColumn = "*";
			sqlDo = sql;
		}
		
		String strVal = "select * from (select " + sqlColumn + ",ROW_NUMBER()";
		strVal += " Over(order by " + orderby + ")";
		strVal += " as rowNum " + sqlDo + ")";
		strVal += " as myTable where rowNum between " + start + " and " + end;

		return strVal;
	}

	public int getRowCount(String sql) throws SQLException {
		
		String sqlDo = "";
		if(sql.indexOf("@#") != -1) {
			String []sqlArr = sql.split("@#");
			sqlDo = sqlArr[1];
		} else sqlDo = sql;
		
		int count = 0;
		try 
		{
			rs = this.returnResultSet("select count(*) " + sqlDo, null, false);
			while (rs.next()) count = rs.getInt(1);
		} 
		catch (Exception ce) { ce.printStackTrace();} 
		finally { clearAllsql(); }
		return count;
	}

	public JDataSet getJDataSetAsPager(String sql, String orderby, int currentPage, int pageSize) {
		
		String strVal = strPager(sql, orderby, currentPage, pageSize);
		return getJDataSet(strVal, null, true, false);
	}

	public JDataSet getJDataSet(String sql, Object[] params, boolean fillColumnNames, boolean executeCall) {
		
		JDataSet jds = null;
		try 
		{
			if (executeCall) rs = returnCs(sql, params).executeQuery();
			else rs = returnPst(sql, params).executeQuery();
			jds = loadJDataSet(rs, fillColumnNames);
		} 
		catch (Exception ex) { ex.printStackTrace(); } 
		finally { clearAllsql(); }
		return jds;
	}
	
	public JDataSet loadJDataSet(ResultSet rs, boolean fillColumnNames) {
		
		JDataSet jds = new JDataSet();
		try 
		{
			int columnCount = returnColumnCount(rs);
			if (fillColumnNames) {
				String[] columnNames = new String[columnCount];
				String[] columnTypeNames = new String[columnCount];
				for (int i = 0; i < columnCount; i++) {
					columnNames[i] = rs.getMetaData().getColumnName(i + 1);
					columnTypeNames[i] = rs.getMetaData().getColumnTypeName(i + 1);
				}
				jds.setColumnNames(columnNames);
				jds.setColumnTypeNames(columnTypeNames);
			}
			while (rs.next()) {
				String[] row = new String[columnCount];
				for (int i = 0; i < columnCount; i++)
					row[i] = rs.getString(i + 1) == null ? "" : rs.getString(i + 1).trim();
				jds.addRow(row);
			}
		} 
		catch (Exception ex) { ex.printStackTrace(); }
		return jds;
	}

}




现在来说下怎么用这个类
比如,你有一个学生类Student.java里面有id,name,age3个属性


public Class Student
{
	private int id;
	private String name;
	private int age;
	
	以下get和set方法省略...
}



你要封装它,你就可以自己定义一个IStudent.java接口extends那个ISqlHelper.java接口
然后来里面定义插入,查询全部,和按id查的功能函数,象如下写的一样
<

当然这样定义很死,最好的方法,就是整理抽象出所有业务类的公用方法,比如,插入,修改,删除。
然后把这些方法在一个公用的操作接口中定义,这个公用的操作接口可以继承ISqlHelper.java接口
然后以后业务类或是数据实体操作类都可以实现这个公用的操作接口。

>


public interface IStudent extends ISqlHelper<Student>
{
	//插入Student
	public boolean insertStudent(Student stu);

	//查询全部Student
	public List<Student> findStudent();

	//按id查询某一个Student
	public Student findStudentAsId(int stuid);
}




并写一个StudentBO.java业务类extends那个SqlHelper和自己定义的IStudent接口
象如下写的一样:


public Class StudentBO extends SqlHelper<Student> implements IStudent
{
	
	protected Student loadDataBean(ResultSet rs, String viewName) throws SQLException;
	{
		Student stu = loadDataBeanSelf(ResultSet rs);
		return stu;
	}

	protected Student loadDataBeanSelf(ResultSet rs) throws SQLException;
	{
		Student stu = new Student();
		stu.setId(rs.getInt("id"));
		stu.setName(rs.changeFont(rs,"name"));
		stu.setAge(rs.getInt("age"));
		
		return stu;
	}

	//实现:插入Student的函数
	public boolean insertStudent(Student stu)
	{
		String sql = "insert into Student(id,name,age) values(?,?,?)";
		Object [] params = new Object[]{stu.getId(),stu.getName,stu.getAge};
		return this.execute(sql, params, false);
	}

	//实现:查询全部Student
	public List<Student> findStudent()
	{
		String sql = "select * from Student";
		return this.findList(sql, null, "",false);
	}

	//实现:按id查询某一个Student
	public Student findStudentAsId(int stuid)
	{
		String sql = "select * from Student where id=" + stuid;
		return this.find(sql, null, "",false);
	}
}



loadDataBean,loadDataBeanSelf是从SqlHelper里继承下来的抽象方法。
必须实现。这就是利用了模版方法模式写出来的。
也就是说,以后你自己写函数的时候,只要在接口里定义,
然后在这样的BO类里写实现它,而且就写那么一点语句就完成了。大大省时省力。

好了这样就完成了,代码是不是看上去又清楚又整洁,如果查找和维护。而且大大减少了那些功能代码和封装象Student.java这样数据实体的代码。一次封装无须在写。

大家肯定有疑问,那就是
this.execute
this.findList
this.find
三个函数哪来的,里面都做了些什么
首先要说他们3个肯定是SqlHelper里被实现过的函数
至于他们怎么实现的,你仔细看下就全明白了。


为什么要多出一个loadDataBean来,大家都看到了,他有一个参数viewName,这里就是用到这个参数的地方,因为大家操作数据库不可能就是那么一张表的操作,有时候会有2到3张表联查,那么用这个参数来判断是哪个函数查出不一样的结果,那么你在这个函数里利用这个参数引进别的xxxBO的loadDataBeanSelf函数,不就可以不用再次重新写那些讨厌的实体封装代码了吗。重用性大大提升。

注意一点,这里的查询是只能全查,如果只需要几个字段,就只能手动自己写咯,其实我是想写一个通用的想查几个字段就几个字段的封装方法,但我懒,所以到现在都没去写

其实还有很多应用和问题,这些我在这里也说不完,希望大家多多交流。


我还会给出我自己当初写的数据库连接池类,希望这些简单的代码能给java新手以帮助。
而且如果大家觉得有问题有意义,一定要发帖指出。哪里好哪里不好
希望大家多多给出看法,多多益善。

在这里还要感谢论坛中yangguo兄,其实我当时写这段代码的主要目的
就是dbutils框架所实现的一个最重要功能
只提交sql语句,然后的数据自动填充到所需要的实体中。而不要在写那么多繁琐的实体封装代码。


这个是源码例子,希望大家能明白这样写的用意,值得探讨。
分享到:
评论
69 楼 ekian 2011-04-01  
刚出道已有这功力了。。LZ这是多久的积累啊?
68 楼 艳沐石 2011-03-31  
kanny87929 写道
艳沐石 写道
对于初学者,是一个很大的帮助。
好的编码规范,在以后编程中受益匪浅。

我自己也写过类似的模块,后来遇到一个老师指点,应该把事务加入,而且尽量让程序耦合程度降低。自己考虑了很久,也没有把这些类重构好。呵呵。

不知道lz有没有相关的考虑呢?



事务是现用现写。
设计上的事这里就不多讨论了。



我真心希望你能给我解释一下设计的问题。在这个问题上,我挺纠结的。或者你也可以给我一些建议。谢谢。
67 楼 kanny87929 2011-03-31  
艳沐石 写道
对于初学者,是一个很大的帮助。
好的编码规范,在以后编程中受益匪浅。

我自己也写过类似的模块,后来遇到一个老师指点,应该把事务加入,而且尽量让程序耦合程度降低。自己考虑了很久,也没有把这些类重构好。呵呵。

不知道lz有没有相关的考虑呢?



事务是现用现写。
设计上的事这里就不多讨论了。

66 楼 Technoboy 2011-03-31  
呵呵,比较的奇怪
65 楼 艳沐石 2011-03-31  
对于初学者,是一个很大的帮助。
好的编码规范,在以后编程中受益匪浅。

我自己也写过类似的模块,后来遇到一个老师指点,应该把事务加入,而且尽量让程序耦合程度降低。自己考虑了很久,也没有把这些类重构好。呵呵。

不知道lz有没有相关的考虑呢?
64 楼 fangshengcai001 2011-03-31  
楼主给力啊    08年刚出道时我还复制黏贴呢
63 楼 kanny87929 2011-03-30  
不错又有人关注了。
62 楼 wuxing429 2011-03-30  
不错 不错  希望更多人给出源码
61 楼 kanny87929 2011-03-12  
lgm277531070 写道
68. 
69.    /** 
70.     * 为了方便操作,我还特意写定义了这个返回ResultSet的方法,便于直接操作 
71.     * @param sql 
72.     * @param params 
73.     * @param executeCall 
74.     * @return 
75.     * @throws SQLException 
76.     */ 
77.    public ResultSet returnResultSet(String sql, Object[] params, boolean executeCall) throws SQLException;  


我被这个雷到了,还能返回ResultSet结果集?????
那方法里面的结果集你没关闭么???如果关闭了,还怎么能返回呢???



这个方法的ResultSet对象,是没有关闭的,所以要在自己的方法里自行关闭。
60 楼 lgm277531070 2011-03-11  
68. 
69.    /** 
70.     * 为了方便操作,我还特意写定义了这个返回ResultSet的方法,便于直接操作 
71.     * @param sql 
72.     * @param params 
73.     * @param executeCall 
74.     * @return 
75.     * @throws SQLException 
76.     */ 
77.    public ResultSet returnResultSet(String sql, Object[] params, boolean executeCall) throws SQLException;  


我被这个雷到了,还能返回ResultSet结果集?????
那方法里面的结果集你没关闭么???如果关闭了,还怎么能返回呢???
59 楼 jiluo093 2011-03-11  
问一个问题啊,我在用tomcat6+ssh+jotm测试jta时,如果两个数据源都是基于MySQL的就可以,如果一个是MySQL,一个是SqlServer,就不能回滚,请问哪位遇到过吗????
58 楼 xymeng0626 2011-03-11  
强烈鄙视几年前写的某某程序,毛意思吗
57 楼 faye.feelcool 2011-03-11  
出道能写这样的代码不错了!
如果论模式,我无话可说。
但是论面向对象设计,我认为你那个什么bean都要继承什么sqlhelp的继承纯粹为继承而继承,我没有看到非要继承的理由。
只是封装对jdbc的访问,其实他本身只是工具类。如果是为了那个connection的话,你又未达到屏蔽jdbc的目的。
使用jdbc编程最容易出错的是连接管理的问题。
也就是说你的封装不完全,而且你的侵入性太高,对后续修改不利,移一发而动全身。
56 楼 kanny87929 2011-03-11  
yangguo 写道
虽然楼主的书面表达看起来有点蛋疼,但代码还是玩得不错的。建议看下dbutils的源码,那才是上佳之作。

又仔细看了下,发现viewName这种设计比较傻瓜,不如没有。

单就你这里的设计,可以搞成:

//SqlHelper<T>改造如下,去掉loadDataBeanSelf

protected T loadDataBean(ResultSet rs, List<SqlHelper<?>> otherBOs){
	T parent = loadBean(rs);
	for(SqlHelper<?> bo : otherBOs){
		Object child = bo.loadBean(rs);
		BeanUtil.setXvalue(parent,child);  //为某对象某个类型设置值。
	}
	
};

protected abstract T loadBean(ResultSet rs);




protected Book loadBean(ResultSet rs)
			throws SQLException {
		
		Book book = new Book();		
		book.setBook_id(rs.getInt("book_id"));
		book.setBook_name(this.changeFont(rs, "book_name"));
		book.setBook_price(rs.getDouble("book_price"));
		book.setStu_id(rs.getInt("stu_id"));	
		return book;
}




以上只是半伪码,未经测试。若在项目中使用,后果自负。





这个建议蛮好
55 楼 kanny87929 2011-03-11  
whaosoft 写道
有一点想问 持久在哪里 lz如何理解何为持久?


数据库就是一个可以持久性保存数据的容器
操作数据库的这层代码就可以理解为持久层操作代码
54 楼 kanny87929 2011-03-11  
马伽角 写道
干嘛不用反射来做呢,,反射来生成SQL



到目前2个人提出要用反射来弄,你有思路?
53 楼 kanny87929 2011-03-11  
huyaohua 写道
kanny87929 写道
huyaohua 写道
我说怎么代码这么熟悉,看楼下才想起.NET,API来!楼主3年前,写成这样已经很强了。不过还是有个建议,楼主对异常的处理还有些问题,对于SQL异常,我的建议或者封装异常,抛出,或者直接运行时异常。



你怎么处理呢,能给出源码不

其实这只是我个人习惯,对于异常的处理,尤其是这种底层的不习惯于  e.printStackTrace();
还有是我的错觉吗,怎么感觉connection为公有变量,在多线程下对同一个实例操作,应该会有问题吧。虽然实际应用中没有人会这么用。



你觉得在什么情况下会发生多线程的情况
52 楼 frankiegao123 2011-03-11  
把数据库连接对象作为成员变量而存在,在并发环境中应该会出现连接关不了的情况。
51 楼 yangguo 2011-03-10  
虽然楼主的书面表达看起来有点蛋疼,但代码还是玩得不错的。建议看下dbutils的源码,那才是上佳之作。

又仔细看了下,发现viewName这种设计比较傻瓜,不如没有。

单就你这里的设计,可以搞成:

//SqlHelper<T>改造如下,去掉loadDataBeanSelf

protected T loadDataBean(ResultSet rs, List<SqlHelper<?>> otherBOs){
	T parent = loadBean(rs);
	for(SqlHelper<?> bo : otherBOs){
		Object child = bo.loadBean(rs);
		BeanUtil.setXvalue(parent,child);  //为某对象某个类型设置值。
	}
	
};

protected abstract T loadBean(ResultSet rs);




protected Book loadBean(ResultSet rs)
			throws SQLException {
		
		Book book = new Book();		
		book.setBook_id(rs.getInt("book_id"));
		book.setBook_name(this.changeFont(rs, "book_name"));
		book.setBook_price(rs.getDouble("book_price"));
		book.setStu_id(rs.getInt("stu_id"));	
		return book;
}




以上只是半伪码,未经测试。若在项目中使用,后果自负。


50 楼 yanaicheng 2011-03-10  
不错的,说明就有自己想法,很不错

相关推荐

    hibernate反向工程模板(已修改)

    在Java Web开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。其中,反向工程(Reverse Engineering)是Hibernate提供的一项功能,它能根据数据库结构自动生成对应的Java实体类、...

    持久层用户开发手册模板.pdf

    《持久层用户开发手册》是中国软件与技术服务股份有限公司应用产品研发中心提供的一份详细的技术文档,旨在帮助开发者理解和使用持久层进行数据库操作。手册的核心内容涵盖了持久层的基本概念、设计目标、开发流程、...

    java网页开发模板

    MyBatis则是一个持久层框架,它将SQL语句与Java代码分离,提供了更加灵活的数据库操作方式。 此外,开发过程中还需要注意前端技术的运用,比如Bootstrap是一个流行的CSS框架,用于创建响应式布局和移动设备优先的...

    Java考勤系统源代码

    MyBatis是一个持久层框架,它简化了SQL操作,允许开发者直接编写SQL语句,将数据库操作与业务逻辑分离。在Java考勤系统中,MyBatis作为数据访问层,用于执行SQL查询,实现对考勤数据的增删改查操作。 **4. Maven...

    JAVA-mybatis-generator代码自动生成工具

    - **生成Mapper接口**:为每个表生成相应的Mapper接口,包含基本的CRUD操作方法。 - **生成XML映射文件**:生成与Mapper接口相对应的XML配置文件,定义SQL语句和结果映射。 ### 3. 运行流程 1. **配置...

    JAVA上百实例源码以及开源项目源代码

    Java二进制IO类与文件复制操作实例 16个目标文件 内容索引:Java源码,初学实例,二进制,文件复制 Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系...

    java后端优秀简历模板

    5. **持久层框架**:如Hibernate和MyBatis,它们帮助开发者更方便地操作数据库,减少手写SQL,提高开发效率。了解这些框架的优缺点以及如何集成到项目中是关键。 6. **分布式系统**:包括负载均衡、集群、分布式...

    java excel导入导出和模板下载

    - **导入模块**: 这部分代码负责接收用户上传的Excel文件,解析数据,校验格式,然后将数据存储到数据库或其他持久化层。 - **导出模块**: 用户可以根据特定条件请求导出数据,此时服务会查询数据库,将数据填充到...

    java简历模板(详细).pdf

    【Java简历模板详解】 在Java开发领域,一份详尽的简历是展示个人技能和经验的重要途径。本简历的主人公王鹏是一名经验丰富的Java开发工程师,他的技能和经历涵盖了多个方面,包括基础编程、Web开发、ORM框架、...

    基于Java+Springboot+Vue的教务管理系统(源代码+数据库).zip

    Springboot集成的MyBatis或JPA等持久层框架,用于处理数据库操作。在本项目中,数据库的设计与管理至关重要,因为它存储了所有教务信息,如课程安排、学生信息、教师信息等。数据库设计应遵循关系数据库的规范,确保...

    java开源包8

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java+struts代码

    - **JVM(Java虚拟机)**:Java代码需要通过JVM转换为机器码运行,实现“一次编写,到处运行”。 2. **Struts框架** - **MVC模式**:Struts将Web应用分为模型、视图和控制器三个部分,使得各部分职责明确,降低...

    java开源包10

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java web开发简历模板【精选文档】.doc

    "java web开发简历模板【精选文档】" 以下是根据给定的文件信息生成的相关知识点: Java 基础 * 熟练使用 Java 语言进行编程开发 * 对 core Java 有较好的理论基础 * 精通流程控制、多种数据结构、排序算法等 * ...

    天天生鲜_java项目.zip

    4. **MyBatis**:MyBatis是一个持久层框架,它简化了数据库访问,通过XML或注解配置来映射原生信息,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。在本项目中,MyBatis可能...

    FreeMarker 生成Java、mybatis文件

    综上所述,"FreeMarker 生成Java、mybatis文件"是一个利用FreeMarker模板引擎自动化生成Java代码和MyBatis XML配置文件的过程。通过理解和运用这一技术,开发者可以提升工作效率,同时保证代码质量。

    Java个人财务管理系统源码.zip

    - **MyBatis**: 数据持久层框架,用于处理数据库操作,通过XML或注解方式将SQL与Java代码绑定,简化了数据访问。 - **Thymeleaf**: 前端模板引擎,用于动态生成HTML页面,与Spring Boot结合使用,提供便捷的MVC...

    在线通讯录,运用java 开发在线通讯录

    8. **模板引擎**: 为了快速生成动态HTML,可能使用FreeMarker或Thymeleaf等模板引擎,它们允许开发者用Java代码控制HTML结构。 9. **单元测试与集成测试**: 使用JUnit或TestNG进行单元测试,验证每个函数或类的正确...

    基于Java的CSI员工管理系统源码.zip

    - **MyBatis**: 作为持久层框架,它简化了数据库操作,使得SQL与Java代码更好地解耦。 - **Maven**: 项目管理和构建工具,用于自动化构建、依赖管理和项目信息管理。 2. **项目结构**: - `sci_mgr-master`目录...

Global site tag (gtag.js) - Google Analytics