05. DBUtils(数据库操作框架).doc_第1页
05. DBUtils(数据库操作框架).doc_第2页
05. DBUtils(数据库操作框架).doc_第3页
05. DBUtils(数据库操作框架).doc_第4页
05. DBUtils(数据库操作框架).doc_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

DBUtils(数据库操作框架)1、框架分类1)ORM框架:Object Relation Mapping JPA:Java Persistent API,ORM标准(借鉴了Hibernate) Hibernate:非常流行(有两套,一套原有的,一套实现了JPA标准) MyBatis:2010年开始。之前叫做iBatis2)JDBC封装框架 DBUtils Spring JDBC Template2、编写自己的JDBC框架1)了解:数据库元数据的获取(做框架用的),包括DataBaseMetaData、ParameterMetaData、ResultSetMetaData。【注:本文使用的DBCPUtil工具类见数据库连接池(DataSource)一文】 DataBaseMetaDataTestpublic void test1() throws SQLExceptionConnection conn = DBCPUtil.getConnection();DatabaseMetaData dmd = conn.getMetaData();/获取数据库名称、版本String name = dmd.getDatabaseProductName();String version = dmd.getDatabaseProductVersion();System.out.println(name+ +version);/获取数据库默认的隔离级别int isolation = dmd.getDefaultTransactionIsolation();System.out.println(isolation); ParameterMetaDataTestpublic void test2() throws SQLExceptionConnection conn = DBCPUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(?);ParameterMetaData pmd = stmt.getParameterMetaData();/获取SQL语句中参数的个数,其实就是?的个数int count = pmd.getParameterCount();System.out.println(count); ResultSetMetaDataTestpublic void test3() throws SQLExceptionConnection conn = DBCPUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(select * from account);ResultSet rs = stmt.executeQuery();ResultSetMetaData rsmd = rs.getMetaData();/获取结果集的列数int count = rsmd.getColumnCount();System.out.println(count);for(int i = 0;i 0)if(params = null | count != params.length)throw new RuntimeException(请检查参数是否正确);for(int i = 0;i 0)if(params = null | count != params.length)throw new RuntimeException(请检查参数是否正确);for(int i = 0;i count;i +)stmt.setObject(i+1, paramsi);rs = stmt.executeQuery();/根据结果集处理程序(ResultSetHandler)中定义的封装策略封装结果集return rsh.handler(rs);catch(Exception e)throw new RuntimeException(e);finallyrelease(rs, stmt, conn); 结果集处理程序:org.flyne.dbassist.ResultSetHandlerpublic interface ResultSetHandler /* * 结果集的封装策略:如何把结果中的数据封装到指定的对象中 * param rs * return 封装了数据的对象 */Object handle(ResultSet rs); 框架提供的ResultHandler的两种实现public class BeanHandler implements ResultSetHandler private Class clazz;public BeanHandler(Class clazz) this.clazz = clazz;public Object handle(ResultSet rs) Object bean = null;try if (rs.next() bean = clazz.newInstance();ResultSetMetaData rsmd = rs.getMetaData();int count = rsmd.getColumnCount();for (int i = 0; i count; i+) String cname = rsmd.getColumnName(i + 1);Object obj = rs.getObject(cname);/ 通过反射给bean中的属性赋值Field f = clazz.getDeclaredField(cname);f.setAccessible(true);f.set(bean, obj);return bean; catch (Exception e) throw new RuntimeException(e);-public class BeanListHandler implements ResultSetHandler private Class clazz;public BeanListHandler(Class clazz) this.clazz = clazz;public Object handle(ResultSet rs) List list = new ArrayList();try while (rs.next() Object bean = clazz.newInstance();ResultSetMetaData rsmd = rs.getMetaData();int count = rsmd.getColumnCount();for (int i = 0; i count; i+) String cname = rsmd.getColumnName(i + 1);Object obj = rs.getObject(cname);/ 通过反射给bean中的属性赋值Field f = clazz.getDeclaredField(cname);f.setAccessible(true);f.set(bean, obj);list.add(bean);return list; catch (Exception e) throw new RuntimeException(e);3、DBUtils框架DBUtils是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装。1) QueryRunner类:DBUtils中有个核心类QueryRunner,封装了常用的JDBC操作,其作用类似于上面自定义框架中的DBAssist类,常用方法可分为两组,如下图所示:QueryRunner中update、batch的用法如下:public class Demo private QueryRunner qr = new QueryRunner(DBCPUtil.getDataSource();Testpublic void testAdd() throws SQLExceptionqr.update(insert into account values(?,?),e,3000);Testpublic void testUpdate() throws SQLExceptionqr.update(update account set money = ? where name = ?,50000,e);Testpublic void testDel() throws SQLExceptionqr.update(delete from account where name = ?,e);/批处理插入10条Testpublic void testBatch() throws SQLException/第一维:记录的条数;第二纬:每条记录需要的参数Object params = new Object10;for(int i = 0;i params.length;i +)paramsi = new ObjectN+(i+1),1000*i;qr.batch(insert into account(name,money) values(?,?), params);2)ResultSetHandler接口:代表对结果集(ResultSet)的处理策略,同DBAssist中的ResultSetHandler接口。DBUtils包中提供了很多ResultsetHandler的实现,除了BeanHandler、BeanListHandler外,还有如下一些实现:ArrayHandler:适合结果只有一条的情况。把第一条记录的每列的值封装到一个Object数组中。ArrayListHandler:适合结果有多条的情况。把每列的值封装到Object数组中,把Object放到List中。ColumnListHandler:适合取某列的值。把取到值封装到List中KeyedHandler:查询多条记录。每条记录封装到一个Map中,key:字段名,value:字段值。再把该Map作为value放到另外一个Map中,该Map的key为指定的列值作为key。MapHandler:适合一条结果。封装到一个Map中,key:字段名,value:字段值MapListHandler:适合多条结果。把每条封装到一个Map中,key:字段名,value:字段值,在把Map封装到List中ScalarHandler:适合取结果只有一行和一列的情况。如分页查询时需要获取总记录条数。4、实际开发中如何处理事务( AOP编程)本文还是以实际生活中的转账为例讲解实际开发中事务的处理,使用数据库如下:create table account(id int primary key auto_increment,name varchar(100),balance float);insert into account values(1,a,1000);insert into account values(2,b,1000);1)第一版:直接在业务层实现中处理事务首先必须明确一点,控制事务是业务层的事,而非DAO层,业务层的实现如下:public class BusinessServiceImpl implements BusinessService public void transfer(String sourceAccountName, String targetAccontName,float money) Connection conn = null;try /控制事务由Service层负责conn = DBCPUtil.getConnection();conn.setAutoCommit(false);AccountDao dao = new AccountDaoImpl(conn);/查询A账户、B账户,并修改余额Account sAccount = dao.findByName(sourceAccountName);Account tAccount = dao.findByName(targetAccontName);sAccount.setMoney(sAccount.getMoney() - money);tAccount.setMoney(tAccount.getMoney() + money);/执行更新dao.updateAcount(sAccount);/ int i=1/0; /模拟转账过程中发生异常dao.updateAcount(tAccount); catch (Exception e) if (conn != null) try conn.rollback(); catch (SQLException e1) e1.printStackTrace();e.printStackTrace(); finally if (conn != null) try mit();conn.close(); catch (SQLException e) e.printStackTrace();DAO层的实现如下:public class AccountDaoImpl implements AccountDao /需使用QueryRunner里面支持事务的那组APIprivate QueryRunner qr = new QueryRunner();private Connection conn;/Service层调用DAO层的时候传入Connection对象public AccountDaoImpl(Connection conn)this.conn = conn;public Account findByName(String sourceName) try return qr.query(conn, select * from account where name = ?, new BeanHandler(Account.class),sourceName); catch (SQLException e) throw new RuntimeException(e);public void update(Account sAccount) try qr.update(conn, update account set balance=? where name = ?,sAccount.getBalance(),sAccount.getName(); catch (SQLException e) throw new RuntimeException(e);2)第二版:利用ThreadLocal管理事务(增加TransactionManager类)上面的版本中,由于需要在业务层考虑事务,因此增加了业务层的编码复杂度,并且在业务层出现了Connection对象(本应该只在DAO层出现),本节抽取了事务管理的公共类:TransactionManager类,降低了业务层的编写难度。补充:ThreadLocal类(线程局部变量)/ 特点:一个线程存的东西,只有该线程才能取出来()。/ 模拟ThreadLocal内部实现(理解的关键)public class ThreadLocal/类似Map的结构private Map map = new HashMap();public void set(Object obj)map.put(Thread.currentThread(),obj);public void remove()map.remove(Thread.currentThread();public Object get()return map.get(Thread.currentThread();有关ThreadLocal类,在线程安全问题一节也有提到。 TransactionManager类:封装了事务管理共同的部分,任何用到事务的地方都可以调用该类中提供的方法。public class TransactionManager /利用ThreadLocal存储用户线程对应的连接private static ThreadLocal tl = new ThreadLocal();public static Connection getConnection()Connection conn = tl.get();if(conn = null)/如果tl中不存在该用户线程对应的连接,则创建连接并放入tl中conn = DBCPUtil.getConnection();tl.set(conn);return conn;public static void startTransaction()try Connection conn = getConnection();conn.setAutoCommit(false);/开启事务 catch (SQLException e) e.printStackTrace();public static void rollback()try Connection conn = getConnection();conn.rollback(); catch (SQLException e) e.printStackTrace();public static void commit()try Connection conn = getConnection();mit(); catch (SQLException e) e.printStackTrace();public static void release()try Connection conn = getConnection();conn.close();tl.remove();/必须要将连接同当前线程解绑。这 与服务器实现有关:服务器采用线程池 。 catch (SQLException e) e.printStackTrace(); 改写业务层和DAO层的实现public class AccountServiceImpl implements AccountService private AccountDao dao = new AccountDaoImpl();public void transfer(String sourceName, String targetName, float money) try TransactionManager.startTransaction();/开启事务Account sAccount = dao.findByName(sourceName);Account tAccount = dao.findByName(targetName);sAccount.setBalance(sAccount.getBalance() - money);tAccount.setBalance(tAccount.getBalance() + money);dao.update(sAccount);/int i = 1/0;dao.update(tAccount); catch (Exception e) TransactionManager.rollback();/回滚事务e.printStackTrace();finallyTransactionMmit();/提交事务TransactionManager.release();-业务层实现-DAO层实现-public class AccountDaoImpl implements AccountDao /需使用QueryRunner里面支持事务的那组APIprivate QueryRunner qr = new QueryRunner();public Account findByName(String sourceName) try return qr.query(TransactionManager.getConnection(), select * from account where name = ?, new BeanHandler(Account.class),sourceName); catch (SQLException e) throw new RuntimeException(e);public void update(Account sAccount) try qr.update(TransactionManager.getConnection(), update account set balance=? where name = ?,sAccount.getBalance(),sAccount.getName(); catch (SQLException e) throw new RuntimeException(e);3)第三版:AOP编程关于AOP的知识详见动态代理技术一文。事务、安全、日志等都可以看成系统的交叉业务,AOP的目标就是要使交叉业务模块化。首先,将事务模块化,即TransactionManager类,代码同上。其次,改写系统的业务代码和DAO层代码:public class AccountServiceImpl implements AccountService private AccountDao dao = new AccountDaoImpl();public void transfer(String sourceName, String targetName, float money) Account sAccount = dao.findByName(sourceName);Account tAccount = dao.findByName(targetName);sAccount.setBalance(sAccount.getBalance() - money);tAccount.setBalance(tAccount.getBalance() + money);dao.update(sAccount);/ int i = 1/0; /模拟转账过程中的异常dao.update(tAccount);DAO层的代码同第二版,可以看出业务层已经没有任务事务控制的代码了,只处理具体的业务逻辑。最后,AccountServi

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论