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()
    		先获取连接,在执行相应的操作
  • 相关阅读:
    RocketMQ
    Docker的基本使用
    logstash、ELK
    spring cloud杂文总结
    手写一个starter
    @SpringBootApplication你知多少?
    使用ElasticSearch
    ElasticSearch安装
    啥是ElasticSearch???
    socket、端口、进程的关系
  • 原文地址:https://www.cnblogs.com/codingpark/p/4266468.html
Copyright © 2011-2022 走看看