zoukankan      html  css  js  c++  java
  • 【JDBC】JDBC实战

    项目实战1:工具类(Util)、ROM、DAO设计模型

    功能:
    工具类Util:获得数据库连接,关闭资源
    对象关系映射ROM:实体类(数据库表的映射)
    数据访问对象DAO:数据的底层访问,增删改等
    1).工具类(Util)
    将加载配置文件的代码,转移到static代码块中.[只会在类加载的时候执行一次]
    实现:
    public class JdbcUtil {
    	private static final Properties p= new Properties();
        static {  // 配置文件文件加载   执行一次.
    		InputStream is = null; 	// 1. 输入流
    		try {
    			is = JdbcUtil3.class.getResourceAsStream("/com/baizhi/util/jdbc.properties");
    			p.load(is);  // 2. load方法加载配置文件
    		} catch (IOException e) {
    			throw new RuntimeException("配置文件加载异常!", e);
    		} finally {
    			if (is != null) {
    				try {	is.close();} 
    catch (IOException e) {e.printStackTrace();}
    			}
    		}
    	}
    	public static Connection getConnection() {  //获得连接,返回
    		Connection conn = null;
    		try {
    			Class.forName(p.getProperty("driverClassName")); // 1. 加载驱动
    			conn = DriverManager.getConnection(p.getProperty("url"), p.getProperty("user"), p.getProperty("password"));// 2. 获得conn
    		}catch (Exception e) {
    			throw new RuntimeException("获得数据库连接异常",e);
    		}
    		return conn;
    	}
    	public static void close(ResultSet rs, PreparedStatement pstm,Connection conn) { //资源释放
    		if (rs != null) {
    			try {rs.close();}
    catch (SQLException e) {	throw new RuntimeException("结果集资源释放异常", e);}
    		}
    		if (pstm != null) {
    			try {pstm.close();} 
    catch (SQLException e) {throw new RuntimeException("pstm资源释放异常", e);}
    		}
    		if (conn != null) {
    			try {conn.close();}
    catch (SQLException e) { new RuntimeException("连接资源释放异常", e); }
    		}
    	}
    }
    2).DAO、ORM模型设计
    ① ORM模式设计:O(Object) R(Relational) M(Mapping)
    面向对象思想,作用是将数据库中的数据,封装成java对象,便于管理.
    
    封装数据库数据的类设计原则:
    Entity(实体): 封装表中的数据.   		Table:存储数据    
    类(Person)                      		表(t_person)      
    1个类创建的对象                		一行数据          
    private 属性(变量命令:stuName)  		列/字段(stu_name) 
    属性提供set/get方法                               
    提供无参和有参构造方法                            
    实体类实现Serializable接口                        
    
    标准示例代码:
    数据库表[创建]:
    create table T_PERSON(
      id      NUMBER(10) primary key,
      name    VARCHAR2(50),
      sex     NUMBER(1),
      age     NUMBER(3),
      mobile  VARCHAR2(11),
      address VARCHAR2(200)
    )
    
    实体类[书写]:
    public class Person implements Serializable{//表
        private Integer id;//字段id
        private String name;//字段name
        private Integer sex;//字段sex
        private Integer age;//字段
        private String mobile;//字段
        private String address;//字段
        
        public Person(){} //无参构造
        public Person(...){...}  //有参构造
        
        //get和set方法(必须标准的set和get)...
    }
    ② DAO模式设计:D(Data) A(Access) O(Object)  数据访问对象
    封装数据库(某张表)访问所有操作。 命名: XxxxDAO
    功能:添加(将对象添加到数据库一行),删除,选择(选择后封装一个对象),选择所有(用List集合)
    	事例:
    public class PersonDAO {
    	//删除数据库中person表中的1条数据根据id
        public void delete(Integer id){
            //1. 获得conn
            //2. 创建pstm : delete from t_person where id = ?
            //3. 绑定参数
            //4. 发送参数  执行sql
            //5. 释放资源
        }
    }
    

    项目实战2:软件三层架构(视图层(View)、业务逻辑层(Service)、数据访问层(DAO))

    编码标准: 
    1. 数据访问对象:DAO
       命令: XxxxDAO
       功能: 面向数据库操作,封装数据库访问.
       思路: 每个数据库访问,每个sql执行,对应DAO的一个方法.
       模板:
      public class XxxDAO{
          public void insert(实体){
              try{
                   1. 获得连接
                   2. 创建pstm  指定sql
                   3. 绑定参数
                   4. 发送参数,执行sql
              }catch(Exception e){
                  throw new RunTimeException(e);
              }finally{ 5. 释放资源(不能关闭),Connection对象可在Service层关闭,但必须与Service层用同一个数据库连接对象 }
          }
          public void delete(id){ }    
          public void update(实体){ }
          public 实体 selectById(id){ }
          public List<实体> selectAll(){ }
       }
    2. 业务对象: Service (Biz)
       命名: XxxxService
       功能: 面向业务实现用户的功能,实现事务
       思路: 一个功能对应一个方法   
       核心关注: ①service方法设计(函数名,参数,返回值)、②service方法的具体实现思路[调用dao]
    
       模板:
       public class XxxService{  
           //1. 一个业务功能对应Service一个方法.
           public 返回值  方法名(参数){
              调用dao完成业务功能  
    //有事务控制时:需要Connection对象的setAutoCommit()/commit(),
    //但必须和Dao获得的是统一个conn可以使用线程空间(ThreadLocal<T>)
    代码下面有演示
           }
       }
    3. 视图层:View
    	展示给用户的界面,并且与service层交互。例如网页,可以操作查询等,
        
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    实例代码:
    配置文件:conf.properties代码:
    	driverClassName=oracle.jdbc.OracleDriver
    url=jdbc:oracle:thin:@localhost:1521:orcl
    user=hr
    password=Oracle123
    
    工具类JdbcUtil代码: //在下面目录有连接池的使用
    public class JdbcUtil {
    	private static final Properties prop = new Properties();
    	private static final ThreadLocal<Connection> tdl = new ThreadLocal<Connection>(); 
    	static {
    		InputStream is = null;
    		try {
    			is = JdbcUtil.class.getResourceAsStream("/com/baizhi/properties/jdbc.properties");
    			prop.load(is);
    			Class.forName(prop.getProperty("driverClassName"));
    		} catch (Exception e) {
    			throw new RuntimeException("加载驱动异常", e);
    		} finally {
    			if(is != null) {
    				try {	is.close();	} catch (IOException e) {	throw new RuntimeException("关闭流异常", e);}
    			}
    		}
    	}
    	public static Connection getConnection() {
    		Connection conn = null;
    		try {
    			conn = tdl.get();
    			if(conn == null) {
    				conn = DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("user"), prop.getProperty("password"));
    				tdl.set(conn);
    			}
    		} catch (SQLException e) {
    			throw new RuntimeException("获得数据库连接异常", e);
    		}
    		return conn;
    	}
    	public static void close(ResultSet rs, PreparedStatement psmt, Connection conn) {
    		if(rs != null) {
    			try {	rs.close();	} catch (SQLException e) {throw new RuntimeException("关闭结果集异常", e);	}
    		}
    		if(psmt != null) {
    			try {	psmt.close();} catch (SQLException e) {throw new RuntimeException("关闭psmt异常", e);}
    		}
    		if(conn != null) {
    			try {
    				conn.close();
    				tdl.remove();
    			} catch (SQLException e) {
    				throw new RuntimeException("关闭数据库连接异常", e);
    			}
    		}
    	}
    }
    数据访问层DAO代码:
    public class AccountDAO { 
    	public Account selectById(String cardId) {	//利用cardid查询
    		Account account = new Account();
    		Connection conn = null;
    		ResultSet rs = null;
    		PreparedStatement psmt = null;
    		try {
    			conn = JdbcUtil.getConnection();
    			psmt = conn.prepareStatement("select * from t_account where cardid = ?");
    			psmt.setString(1, cardId);
    			rs = psmt.executeQuery();
    			rs.next();
    			account = new Account(rs.getString("cardid"), rs.getString("username"), rs.getString("password"), rs.getDouble("balance"));
    		} catch (SQLException e) {
    			throw new RuntimeException("查询数据库异常", e);
    		} finally {
    			JdbcUtil.close(rs, psmt, null); // Connection在Service层关闭 --原子性;
    		}
    		return account;
    	}
    	//查询所有
    	public List<Account> selectAll() {
    		List<Account> list = new CopyOnWriteArrayList<Account>();
    		Connection conn = null;
    		PreparedStatement psmt = null;
    		ResultSet rs = null;
    		try {
    			conn = JdbcUtil.getConnection();
    			psmt = conn.prepareStatement("select cardid, username, password, balance from t_account");
    			rs = psmt.executeQuery();
    			while(rs.next()) {
    				list.add(new Account(rs.getString("cardid"), rs.getString("username"), rs.getString("password"), rs.getDouble("balance")));
    			}
    		} catch(Exception e) {
    			throw new RuntimeException("查询所有信息异常", e);
    		} finally {
    			JdbcUtil.close(rs, psmt, null); //Connection在Service层关闭 --原子性
    		}
    		return list;
    }
    }
    业务逻辑层Service代码:
    public class AccountService {
    	//查询所有账户
    	public List<Account> findAll() {
    		List<Account> list = new CopyOnWriteArrayList<Account>();
    		Connection conn = null;
    		try {
    			conn = JdbcUtil.getConnection();
    			conn.setAutoCommit(false);
    			AccountDAO accountDAO = new AccountDAO();
    			list = accountDAO.selectAll();
    			conn.commit();
    		} catch(Exception e) {
    			try {	conn.rollback();} catch (SQLException e1) {throw new RuntimeException("回滚错误", e);}
    			throw new RuntimeException("查询所有账户异常", e);
    		} finally {
    			JdbcUtil.close(null, null, conn);
    		}
    		return list;
    	}
    	//根据id查询 
    	public Account findById(String cardId) {
    		Account account = null;
    		Connection conn = null;
    		try {
    			conn = JdbcUtil.getConnection();
    			conn.setAutoCommit(false);
    			AccountDAO accountDAO = new AccountDAO();
    			account = accountDAO.selectById(cardId);
    			conn.commit();
    		} catch(Exception e) {
    			try {	conn.rollback();} catch (SQLException e1) {throw new RuntimeException("回滚错误", e);}
    			throw new RuntimeException("查询异常", e);
    		}
    		return account;
    	}
    }
    

    项目实战3: (ThreadLocal底层)、编码规范、单元测试、连接优化(连接池)

    1. Thread内部存储结构
       class Thread{
           ThreadLocalMap threadLocals   //Map类型的结构
       }
    
    作用: 操作当前线程内部一块存储空间 (属性)
     借助当前线程Thread共享(传递)数据
    创建: new ThreadLocal<泛型>()
    ① threadLocal.set(值); 将数据存入当前线程
    	
    ② threadLocal.get(); 从当前线程中获取值
    
    ③ threadLocal.remove(); 从当前线程中移除值.
    
    2. 编码规范
    项目包结构规范:
    包接口规范: 公司网址倒置: www.baizhiedu.com
    com.baizhiedu.模块名.xxx
    实体----entity
    JdbcUtil----util
    DAO接口----dao
    DAO接口实现类----dao.impl
    Service接口----service
    Service实现类-----service.impl
    view对象----view
    配置文件----conf
    sql文件----sql
    测试代码----test
     编码步骤:
    0. 导入jar  导入工具类   导入配置文件
    1. 表(数据库设计)
    2. 实体(映射数据库的表)
    3. 开发UserDAO接口:  XxxDAO
    4. 开发UserDAO实现类:  XxxxDAOImpl
    5. 开发UserService接口:  XxxxService
    6. 开发UserService实现类:  XxxxServiceImpl
    7. 开发View
    接口定义:
        作用:
     		1. 对dao和service定义标准.提高代码可维护性.
     		2. 更加符合程序员代码开发思路,先宏观(类 方法声明),再微观(方法实现)
     	DAO开发先写接口.
     	调用: XxxDAO dao = new XxxDAOImpl()
     		 dao.xxx();
     	Service开发先写接口,
    	调用: XxxService service = new XxxServiceImpl()
    		 service.xxx();
    3. 单元测试
    作用: 代码中每个方法单元,书写完毕都要通过测试验证方法可用性.
    Junit测试工具
    使用:
    1. 声明一个方法(没有参数,没有返回值) 
    2. 测试方法上添加`@Test`
    3. 通过junit启动
    4. 连接优化(连接池)
    -连接池: 接口 DataSource (数据源)
    -连接处理的问题:
    ①用户执行代码需要conn,需要等待连接的创建
    ②用户操作完毕,conn.close,宝贵(昂贵)资源,直接销毁.
    -解决思路:
    ①事先为用户准备一定数量的conn,当需要使用conn,直接从区域(连接池)获取conn(免去conn创建需要等待的时间)
    ②conn使用完毕之后,还回到存放conn的区域(连接池)(昂贵的conn资源,重复利用)
    -作用: 事先创建一定数量的连接放入连接池,使用只接获取,无需等待.
    -常见连接池:  dbcp c3p0   tomcat-pool   阿里Druid
    -阿里druid连接池(使用):
    导入druid相关的jar
    ①创建Datasource(连接池)
       	DataSource ds = DruidDatasourceFactory.createDatasource(包含了连接池配置信息的Properties);
    ②DataSource中获得连接
    Connection conn = ds.getConnection();//只接获得连接池中的conn
    		修改以上的JdbcUtil工具类代码:
    配置文件conf.properties代码:
    	driverClassName=oracle.jdbc.OracleDriver
    url=jdbc:oracle:thin:@localhost:1521:orcl
    user=hr
    password=Oracle123
    initialSize=10;
    maxActive=50;
    maxWait=6000;
    工具类JdbcUtil代码:
    package com.baizhi.util;
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    import javax.sql.DataSource;
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    public class JdbcUtil4 {
    	private static final Properties props = new Properties();
    	private static final ThreadLocal<Connection> tdl = new ThreadLocal<Connection>();
    	private static DataSource ds = null;
    	static {
    		InputStream is = null;  // 1. 输入流
    		try {
    			is = JdbcUtil4.class.getResourceAsStream("/com/baizhiedu/user/conf/druid.properties");
    			props.load(is);  // 2. load方法加载配置文件--- props存放连接池相关配置信息
    			ds = DruidDataSourceFactory.createDataSource(props);  //3. 创建连接池
    		} catch (Exception e) {
    			throw new RuntimeException("配置文件加载异常!", e);
    		} finally {
    			if (is != null) {
    				try {	is.close();	} 
    catch (IOException e) {e.printStackTrace();}
    			}
    		}
    	}
    //获得数据库连接
    	public static Connection getConnection() {
    		Connection conn = null;
    		try { 	//从当前线程获得conn
    			conn = tdl.get();
    			if(conn == null){
    				conn = ds.getConnection();  //从连接池获得连接
    				tdl.set(conn);   //将连接存入当前线程
    			}
    		}catch (Exception e) {
    			e.printStackTrace();
    			throw new RuntimeException("获得数据库连接异常",e);
    		}
    		return conn;
    	}
    	//释放资源: 关闭 rs pstm conn   
    	public static void close(ResultSet rs, PreparedStatement pstm,Connection conn) {
    		// 对rs pstm conn
    		if (rs != null) {
    			try {	rs.close();	} 
    catch (SQLException e) {	throw new RuntimeException("结果集资源释放异常", e);}
    		}
    		if (pstm != null) {
    			try {	pstm.close();} 
    catch (SQLException e) {	throw new RuntimeException("pstm资源释放异常", e);}
    		}
    		if (conn != null) {
    			try {	conn.close();//将conn从当前线程移除,是复写的close方法
    				tdl.remove();
    			} catch (SQLException e) {throw new RuntimeException("连接资源释放异常", e);}
    		}
    	}
    }
    连接池:补充说明
    1. 连接返回给连接池.
       	conn.close()
    说明: 调用的连接池封装的Connection对象的close方法,方法内部操作未断开连接,将内部conn放回到连接池.
    2. 连接池内部的连接类设计
       	从连接池中获得conn是连接池自己封装的conn类.
      	 // 代理设计模式
       	public class DruidConnection implements Connection{
       	    private Connection oracleConnection = null;
       	    public preparedStatement(){}
      	    public void close(){
              	DataSource.recycle(oracleConnection);
           	}
       	}
       	public class DruidDataSource implements DataSource{
           	private List<Connection> conns;
       	}
    
  • 相关阅读:
    操作 Java 数组的 12 个最佳方法
    详解 JavaScript 中 splice() 方法
    Java 读取 .properties 配置文件的几种方式
    表单中单选、多选、选择框值的获取及表单的序列化
    一个调出上下文菜单的实例
    跨浏览器的事件侦听器和事件对象
    动态加载js和css
    php语言实现的7种基本的排序方法
    CORS(跨源资源共享)实战
    ubuntu中LAMP环境搭建及ubuntu语言和输入法设置
  • 原文地址:https://www.cnblogs.com/jwnming/p/13634762.html
Copyright © 2011-2022 走看看