zoukankan      html  css  js  c++  java
  • JavaWeb之JDBC&自定义框架/DBUtil(十五)

    简介

    关于代码方面,可能在今后博客中很少写,因为我尽量把代码体现成思路出来。以便以后复习看着思路写代码。其实代码成篇贴上去也未必有心思看下去,不如思路来得实际

    自定义框架

    1. 编写简单自定义框架,简化数据访问层操作

    1. 准备环境
    	1.1 jar包	c3p0-0.9.1.2.jar/mysql-connector-java-5.0.8-bin.jar
    	1.2 需要获取数据源(这里使用c3p0获取)C3P0Util.java/相应的配置文件c3p0-config.xml
    
    2. 	开发简单框架简化DAO操作DBAssist类
    	1>. 降低依赖性,这里数据源获取由外部传入,由构造接收对成员属性进行赋值
    		private static DataSource ds;
    		public DBAssist(DataSource ds) {
    			this.ds = ds;
    		}
    3. 因为CUD操作方式一样,唯一不一样的是参数个数,所以这里可以定义一个方法对CUD进行操作
    	定义方法void update(String sql, Object...params)
    		3.1 通过数据源获取数据库连接
    		3.2 获取执行sql语句对象
    		3.3 通过该对象获取参数元数据信息
    			ParameterMetaData rsmd = stmt.getParameterMetaData();
    			得到参数个数int count = rsmd.getParameterCount();
    		3.4 判断参数个数是否与objs对应的参数值是否一致
    			1). 首先判断参数个数(count)是否大于0
    			2). 判断接收的参数是否为空或小于0/再判断接收的参数和参数个数是否相等
    			3). 否则匹配条件,则遍历参数,对每个参数进行赋值(值为接收的参数)
    		3.5 执行语句	stmt.executeUpdate();
    		3.6 释放资源		C3P0Util.release(null, stmt, conn);
    	
    4. 查询结果集
    		定义方法Object query(String sql,ResultSetHandler rsh ,Object...params)
    		重复3.1-3.4步骤
    		4.5 执行结果集stmt.executeQuery();
    		4.6 将结果集转成Object对象返回
    			
    		
    5. 	延续4.6步骤将结果集转成Object对象返回	
    	5.1 建立接口ResultSetHandler,结果处理器这种模式就是策略设计模式,抽象策略
    		public interface ResultSetHandler {
    			Object handler(ResultSet rs);
    		}
    	5.2 建立与数据库相应的JavaBean类
    	5.3 建立BeanHandler类,适用于结果集只有一条记录的情况,如果结果集有多条记录,只返回第一条要封装的目标类型,需要调用者传回来,JavaBean的字段名与数据库列名保持一致和对应,而且JavaBean有默认构造方法
    		使用装饰对要注入的类进行接收
    			private Class clazz;
    			public BeanHandler(Class clazz) {
    				this.clazz = clazz;
    			}
    	5.4 将结果集转换对象的方法Object handler(ResultSet rs)
    		1). 首先创建要注入类的实例	obj = clazz.newInstance();
    		2). 获取结果集的元信息,通过元信息获取个数
    			ResultSetMetaData rsmd = rs.getMetaData();
    			int count = rsmd.getColumnCount();
    		3). 遍历每个参数
    			获取列名和列值
    					String columnName = rsmd.getColumnName(i+1);
    					Object columnValue = rs.getObject(i+1);
    			通过反射将列值设置到注入类的属性中
    				Field field = clazz.getDeclaredField(columnName);
    				field.setAccessible(true);
    				field.set(obj, columnValue);
    				
    6. 查询所有结果集BeanListHandler和查询单个结果集唯一不同的是需要定义一个集合
    	6.1 定义集合用作存储每个结果集
    	6.2 区别1,将if修改为while,就是代表遍历每一行数据
    	6.3 将每一行的结果集添加到list集合中

    ORM(对象关系映射)

    1. ORM是什么?

    ORM(Object/Relation Mapping)就是对象-关系的映射,对象就是Java这种面向对象语言,关系就是关系型数据库,其实就是把一个对象映射成表的一行记录,再把表的一行记录映射成Java中的一个对象。这就是ORM的用途!

    2. ORM是什么?

    1. Apache commons DBUtils:很简单的JDBC框架,很多公司在使用它,就是因为它内容很简单,也很方便;
    2. Hibernate(全自动):SSH中的H就是它了,它的HQL号称是面向对象的查询语言;
    3. Ibatis(半自动):简单、方便!很多人用“全自动”形容Hibernate,那么对Ibatis就是“半自动”了。Hibernate把面向关系的东西都封装起来了,甚至你可能对SQL不是很了解都可以通过Hibernate来操作数据库!但是,有是我们还是需要自己来通过面向关系(打开封装)来完成一些特殊的操作,那么“半自动”的Ibatis就派上用场了;
    4. Spring-JDBC(基本与DBUtils是一个级别的,很简单的封装):Spring中的JDBC框架与dbUtils很相似!但是Spring的IoC给Spring-JDBC做了强大的后盾,并且Spring通过AOP对声明式事务的处理可以说是为人能比,所以,Spring的JDBC框架还是很有用途的;
    5. EJB(Entity Bean)(老了):Java EE中的实体Bean,因为是重量级组件,现在已经很少使用了。
     

    DBUtils

    1 DBUtils简介

    DBUtils是Apache Commons组件中的一员,开源免费!
    DBUtils是对JDBC的简单封装,但是它还是被很多公司使用!
    DBUtils的Jar包:dbutils.jar

    2 DBUtils简介

    DbUtils:都是静态方法,一系列的close()方法;
    QueryRunner:提供update()、query()、batch()方法;
    
    QueryRunner的query()方法也需要ResultSetHandler来映射结果集
    
    1. 批处理使用:
    	public void testBatch() {
    		Object[][] params = new Object[10][];
    		for(int i=0; i<params.length; i++) {
    			params[i] = new Object[]{i,"web"+i,1000.00f};
    		}
    		try {
    			qr.batch("insert into t3 values(?,?,?)",params);
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    
    2. query常用三种使用:
    	2.1 public void testBeanHandler() {
    			Account a = new Account();
    			a = qr.query("select * from t4 where id=?", new BeanHandler(a.getClass()),1);
    			System.out.println(a);
    		}
    	2.2 public void testBeanListHandler() {
    			List<Account> accounts = new ArrayList<Account>();
    			accounts = qr.query("select * from t4", new BeanListHandler<Account>(Account.class));
    			System.out.println(accounts);
    		}
    	2.3 public void testScalarHandler2() {
    			int totalRecordes =  ((Long) qr.query("select count(*) from t3", new ScalarHandler())).intValue();
    			System.out.println(totalRecordes);	//获取总条数,分页时使用
    		}

    3 DBUtils与事务处理

    con.setAutoCommit(false); -- 开始
    con.commit(); -- 成功结束
    con.rollback(); -- 失败结束
    
    事务与DBUtil简单使用,下面一个示例会加深理解,这里只作简单理解
    private QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
    
    public void transfor(int sourceAcc, int targetAcc, float money) {
    	Connection conn = null;
    	try {
    		conn = C3P0Util.getConnection();
    		conn.setAutoCommit(false);
    		qr.update("update account set money=money-? where id=?", money,
    				sourceAcc);
    		int i = 1/0;
    		qr.update("update account set money=money+? where id=?", money,
    				targetAcc);
    		
    		conn.commit();
    	} catch (Exception e) {
    		if(conn != null) {
    			try {
    				conn.rollback();
    			} catch (SQLException e1) {
    				e1.printStackTrace();
    			}
    		}
    	}
    }

    4 Dao和Service中的事务处理(实现用户转账)

    1. 开发前奏
    	1.1 导包/获取数据源工具类,接口,不再重复
    	1.2 步骤JavaBean类-->AccountDaoImpl-->BusinnesServiceImpl<-->BeanFactory<-->TransactionManager
    
    2. 建立账户类(Account)和数据库账户表中字段信息成映射关系
    	private int id;
    	private String name;
    	private float money;
    
    3. 数据访问层专注操作数据中的实现类AccountDaoImpl
    	3.1 使用DBUtil实现获取账户和更新账户功能
    		1). private QueryRunner qr = new QueryRunner();
    		2). Account getAccountById(int id)/ void updateAccount(Account acc)
    		3). 在查询或者更新时指定连接确保是一个数据库连接(这里需要用事务管理中的方法)
    		
    4. 业务逻辑层专注业务操作BusinnesServiceImpl
    	1. 获取dao层对象对数据操作
    	2. 通过姓名获取要转账的账户(源和目的账户)
    	3. 对账户余额进行操作
    	4. 写入到表中updateAccout()
    
    5. 代理业务逻辑层的实现类,实现业务层专注操作业务部分,其他功能由代理对象代理,当使用业务逻辑类时,直接使用代理对象即可
    	1. 定义代理的对象
    	2. 通过动态代理中Proxy类中newProxyInstance(ClassLoader, Interfaces, InvocationHandler)创建代理类
    		1). 对业务方法采采用相应的策略
    			if("transfor".equals(method.getName())) {
    				try {
    					//横向切入要添加的事务
    					TransactionManager.startTransaction();//又称前置通知
    					//保证原有方法能执行
    					Object retVal = method.invoke(service, args);
    					//后置通知
    					TransactionManager.startTransaction();
    					//最终勿忘将代理的对象返回
    				} catch (Exception e) {
    						e.printStackTrace();
    						TransactionManager.rollback();//异常通知
    				}
    				//finally 最终通知
    			}
    			
    6. TransactionManager类,上一步骤提到的事务,应封装到一个事务管理类,专注事务处理
    	当前线程存入的线程局部变量只能当前线程取值
    	其他线程是取不了的
    	1. 定义线程局部变量,用于放连接
    		private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    	2. 获取连接方法,将连接设置到线程局部变量中
    	3. startTransaction()/rollback()/commit()
    		先获取连接,在执行相应的操作
  • 相关阅读:
    May 1 2017 Week 18 Monday
    April 30 2017 Week 18 Sunday
    April 29 2017 Week 17 Saturday
    April 28 2017 Week 17 Friday
    April 27 2017 Week 17 Thursday
    April 26 2017 Week 17 Wednesday
    【2017-07-04】Qt信号与槽深入理解之一:信号与槽的连接方式
    April 25 2017 Week 17 Tuesday
    April 24 2017 Week 17 Monday
    为什么丑陋的UI界面却能创造良好的用户体验?
  • 原文地址:https://www.cnblogs.com/codingpark/p/4266468.html
Copyright © 2011-2022 走看看