Common Dbutils是操作数据库的组件,是一个开源的JDBC工具类库,对传统操作数据库的类进行二次封装,可以把结果集转化成List。
DBUtils是java编程中的数据库操作实用工具,小巧简单实用,没有Hibernate等一些ORM框架的庞大,繁琐的配置。
1.对于数据表的读操作,他可以把结果转换成List,Array,Set等java集合,便于程序员操作; 2.对于数据表的写操作,也变得很简单(只需写sql语句) 3.可以使用数据源,使用JNDI,数据库连接池等技术来优化性能--重用已经构建好的数据库连接对象,而不像php,asp那样,费时费力的不断重复的构建和析构这样的对象。 但是,如果使用dbutils包的话,需要注意以下几点: 1.实体类属性的名称要与库中字段的名字一致,否则无法查到结果。 2.ResultSetHandler rsh = 接口的实现类 如果返回对象的话使用new BeanHandler(); 如果返回的是集合的话使用 new BeanListHandler(); 3.等等可以参考官方文档或其他资料调用主要类
- org.apache.commons.dbutils.QueryRunner
- org.apache.commons.dbutils.ResultSetHandler
- org.apache.commons.dbutils.DbUtils
Dbutils用法
dbutils封装了jdbc的增删改查的操作,只需要new一个QueryRunner,然后调用其query方法,将sql语句,参数或参数数组,传入结果集处理器递。
结果集处理器ResultSetHandler 接口的实现类- ArrayHandler:把结果集中的第一行数据转成对象数组。
- ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
- BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
- BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
- ColumnListHandler:将结果集中某一列的数据存放到List中。
- KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。
- MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
- MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
在mvc模式中,dao层只负责对数据库的操作,不应该有任何业务逻辑的代码,但是有一种情况,比如银行转账,几次数据库操作在一次事务中,在service中如何将转账服务放在一次事务中呢,一种解决办法是在dao层中保存一个Connection,由service传递进来对那个Connection操作,就可以解决这个问题。
在mvc模式下,如何进行事务管理呢,上面的方法是,所有的dao层共享同一事务,即同一连接,实现此需求的另外一种方法是使用ThreadLocale技术,这个对象保存的是一个线程为键的map,如果在dao层中将得到的Connection存放在这个map中,则在service中得到的连接就是同一连接,可以写一个工具类实现获取连接,提交,回滚,关闭等操作。 以上两种方法只能在dao层中实现共享事务,但是如果是servlet转发等情况,便不是同一连接,这时候就必须将事务管理提前到servlet之前,就写一个拦截器,每一次请求都获取连接,然后放行给servlet等,返回时再关闭连接等,缺点是占用连接时间过长,所以使用spring是好的方法,但是比较臃肿。下面例子是dbutils+反射对Dao简单使用
实体类 UserRoleVo.java
public class UserRoleVo { int id; String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "UserRoleVo [id=" + id + ", name=" + name + "]"; }}
基于泛型的BaseDao.java
import java.lang.reflect.ParameterizedType;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.util.List;import org.apache.commons.dbutils.DbUtils;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanListHandler;public class BaseDao{ private static final String CLASSNAME="com.microsoft.sqlserver.jdbc.SQLServerDriver"; private static final String URL="jdbc:sqlserver://127.0.0.1:1433;databasename=MybookShop"; private static final String UID="sa"; private static final String PWD=""; private Class cls; public Connection getConn() throws SQLException { Connection conn=DriverManager.getConnection(URL,UID,PWD); return conn; } public DBM() throws SQLException{ DbUtils.loadDriver(CLASSNAME); cls= (Class)((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } public List query(String sql,Object...paras) throws SQLException{ QueryRunner qr=new QueryRunner(); BeanListHandler handler=new BeanListHandler(cls); Connection conn=getConn(); List list= (List ) qr.query(getConn(), sql,paras , handler); DbUtils.close(conn); return list; } public void update(String sql,Object...paras) throws SQLException{ QueryRunner qr=new QueryRunner(); Connection conn=getConn(); qr.update(conn, sql,paras); DbUtils.close(conn); } }
数据访问层类UserRoleDAO.java:
import java.sql.SQLException;import java.util.List;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanListHandler;import com.accp.db.DBM;import com.accp.vo.UserRoleVo;public class UserRoleDao extends BaseDao{ public UserRoleDao() throws SQLException { super(); } public List findAll() throws SQLException{ return query("select * from userRoles"); } public List findAllByName(String name) throws SQLException{ return query( "select * from userRoles where name like ?","%"+name+"%"); } public void add(UserRoleVo role) throws SQLException{ update("insert into userRoles values (?)",role.getName()); }}
这样的BaseDao就可以很方便地被子类继承使用query(),update()等方法,没有set(),get()繁琐过程就可以得到结果集。其实还可以继续封装像(不过POJO是Bean 类的基类,这样做法好像代码不清晰)但你还是可以用其他办法想上面的例子一样封装操作数据库方法,只不过需要稍稍修改,如
/** * 分页列出所有对象 * @param page * @param size * @return */ public List List(int page, int size) { String sql = "SELECT * FROM " + TableName() + " ORDER BY id DESC"; return QueryHelper.query_slice(getClass(), sql, page, size); } public List Filter(String filter, int page, int size) { String sql = "SELECT * FROM " + TableName() + " WHERE " + filter + " ORDER BY id DESC"; return QueryHelper.query_slice(getClass(), sql, page, size); }/** * 根据主键读取对象详细资料,根据预设方法自动判别是否需要缓存 * @param id * @return */ @SuppressWarnings("unchecked") publicT Get(long id) { if(id <= 0) return null; String sql = "SELECT * FROM " + TableName() + " WHERE id=?"; boolean cached = IsObjectCachedByID(); return (T)QueryHelper.read_cache(getClass(), cached?CacheRegion():null, id, sql, id); } public List BatchGet(List ids) { if(ids==null || ids.size()==0) return null; StringBuilder sql = new StringBuilder("SELECT * FROM " + TableName() + " WHERE id IN ("); for(int i=1;i<=ids.size();i++) { sql.append('?'); if(i < ids.size()) sql.append(','); } sql.append(')'); List beans = QueryHelper.query(getClass(), sql.toString(), ids.toArray(new Object[ids.size()])); if(IsObjectCachedByID()){ for(Object bean : beans){ CacheManager.set(CacheRegion(), ((POJO)bean).getId(), (Serializable)bean); } } return beans; }/** * 插入对象 * @param obj * @return 返回插入对象的主键 */ private static long _InsertObject(POJO obj) { Map pojo_bean = obj.ListInsertableFields(); String[] fields = pojo_bean.keySet().toArray(new String[pojo_bean.size()]); StringBuilder sql = new StringBuilder("INSERT INTO ") ; sql.append(obj.TableName()); sql.append('('); for(int i=0;i 0) sql.append(','); sql.append(fields[i]); } sql.append(") VALUES("); for(int i=0;i 0) sql.append(','); sql.append('?'); } sql.append(')'); PreparedStatement ps = null; ResultSet rs = null; try{ ps = QueryHelper.getConnection().prepareStatement(sql.toString(), PreparedStatement.RETURN_GENERATED_KEYS); for(int i=0;i
这样的话数据层的子类会更加简单,大大减少代码量。
最后我是想说不用Hibernate等一些ORM框架,是感觉用了之后不灵活。