JDBC技术

JDBC技术

一、引言

什么是JDBC?

​ Java数据库连接:使用java程序去访问和操作数据库的一组接口规范。

​ 为什么是接口规范?

​ java程序可能会去访问和操作不同类型的数据库。

​ 接口的好处?

​ 屏蔽了不同数据库实现的代码差异。

​ JDBC接口代码的实现在哪?

​ 有数据库厂商提供 ----> 驱动jar包

​ 连接Oracle数据库, ojdbc14.jar (10g版本) ojdbc5/6

在这里插入图片描述

二、代码的实现思想

Java是一门面向对象的编程语言
在这里插入图片描述

编程步骤

​ 1、环境搭建 (引入驱动jar包)

​ lib —> ojdbc.14 右键 build path ----> add to build path

​ 2、注册驱动

​ Class.forName(“oracle.jdbc.OracleDriver”);

​ 3、创建连接对象

​ @ip地址 : 监听端口port :SID实例名称

​ String url=“jdbc:oracle:thin:@localhost:1521:XE”;

​ Connection conn = DriverManager.getConnection(url, “hr”, “hr”);

​ 4、发送SQL语句

​ //准备SQL语句 交由ps对象
​ String sql=“insert into clazz values(3,‘190班’)”;
​ PreparedStatement ps = conn.prepareStatement(sql);
​ //发送 返回值代表了数据的实际影响行数 一般没啥用 可选择省略
​ int i = ps.executeUpdate();
​ System.out.println(i);

​ 5、接收结果集 (针对查询操作) 略

​ 6、关闭资源

​ 写在finally中

​ if(ps!=null)try {ps.close();} catch (SQLException e) {}
​ if(conn!=null)try {conn.close();} catch (SQLException e) {}

public static void main(String[] args) {
    //1.环境搭建 对于jar包引入 以及add to build path
    Connection conn=null;
    PreparedStatement ps = null;  // Statement 、 SQL注入的问题 
    try {
        //2.注册驱动
        //ClassNotFoundException   1、没有导入驱动jar  2、全限定名称书写错误
        Class.forName("oracle.jdbc.OracleDriver");
        //3.创建连接
        //空指针  换jar包
        //SQLException    用户名密码书写错误  ORA-01017
        //SQLException    The Network Adapter could not establish the connection 
        //            1. ip地址书写错误    2.监听服务没有启动
        conn = DriverManager.
            getConnection("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr");
        //4.准备 并发送SQL语句
        //SQLException   基本上都是SQL语法问题
        String sql = "insert into clazz values(3,'190')";
        ps = conn.prepareStatement(sql);
        ps.executeUpdate();  //返回值代表了DML操作影响的行数
        //5.接收查询结果集  略
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally{
        //6.关闭资源
        if(ps!=null)try {ps.close();} catch (Exception e2) {}
        if(conn!=null)try {conn.close();} catch (Exception e2) {}
    }
}

JUnit 4 测试

​ 一个类中只能存在一个main函数只能测试一个代码方法。

​ JUnit常用测试手段,不适用main函数进行代码的测试书写,选择@Test注解添加入类中的方法,每一个方法都可以视为独立的测试(可以运行)方法。

​ 书写规范!!!!

    Class MyTest{
        @Test
        public void 方法名称随意(){
            //代码、、、、
        }  
        //使用方法替换main函数
    }

三、查询操作

    //4、书写SQL语句 并发送
    String sql="select * from users";
    ps = conn.prepareStatement(sql);
   
	//ResultSet 查询数据的结果集
    rs = ps.executeQuery();
    //5、结果集 进行操作
    //判断是否存在下一行数据     rs.next 方法
    while(rs.next()){
        //存在数据 获取数据     rs.getXXX
        System.out.println(rs.getInt("id"));
        System.out.println(rs.getString("name"));
        System.out.println("-------------------------");
    }

注意: 
		1char varchar varchar2 统一都是  rs.getString()
		2、 rs.getXXX( int / String );
				int : 列的索引    String : 列的名称 (建议)

在这里插入图片描述

四、参数动态化

​ SQL语句中所有的参数数据都是用硬编码形式,需要进行动态替换.

​ 占位符替换 —> 使用 ? 替换数据

​ 书写: 在 ps = conn.prepareStatement(sql); 获取SQL语句之后

​ 在 ps.executeUpdate / Query (); 发送SQL语句之前

        //4.准备 并发送SQL语句
        //SQLException   基本上都是SQL语法问题
        String sql = "insert into users values(?,?)";
        ps = conn.prepareStatement(sql);
        // 使用数据替换?    第一个参数: 替换第几个?   第二个参数 数据值
        ps.setInt(1, 4);
        ps.setString(2, "刘洋");
        //发送
        ps.executeUpdate(); 


五、工具类的封装

常用的配置文件类型

.properties .xml .yml

public class JDBCUtil {
	private static Properties properties = new Properties();
	//对于程序中冗余代码的抽取
	//配置参数写入配置文件进行读取
	//执行效率  静态代码块 会在类加载的时候执行一次 用来读取配置文件
	static{
        // 读取项目中的配置文件 路径: 以src目录为根路径   /   代表根 src           
        //空指针异常
        // NoClassDefFoundError   路径书写错误
		InputStream is = 
            JDBCUtil.class.getResourceAsStream("/com/baizhi/am/jdbc.properties");
		try {
            //将读取的数据加载如集合对象
			properties.load(is);
			is.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	//1、 对于注册驱动 和 连接创建的封装
	public static Connection getConnection()
        	throws ClassNotFoundException,SQLException{	
		Class.forName(properties.getProperty("driver"));
		Connection conn = DriverManager.getConnection(properties.getProperty("url"), 
                          properties.getProperty("username"), 
                          properties.getProperty("password"));		
		return conn;
	}
	
	//2、 资源的关闭的封装
	public static void close(Connection conn,PreparedStatement ps,ResultSet rs){
		if(rs!=null)try {rs.close();} catch (Exception e2) {}
		if(ps!=null)try {ps.close();} catch (Exception e2) {}
		if(conn!=null)try {conn.close();} catch (Exception e2) {}
	}
	
	public static void close(Connection conn,PreparedStatement ps){
		if(ps!=null)try {ps.close();} catch (Exception e2) {}
		if(conn!=null)try {conn.close();} catch (Exception e2) {}
	}
}

六、ORM对象关系映射

数据库中的数据 和 java中对象的 关系。 (编程思想)成为值对象

将数据库获取的数据封装成java程序中的对象方便程序的处理和操作

命名关系?

表名 Users ----> 类名 User (实体类) 一 一 对应关系

在这里插入图片描述

七、DAO设计思想 (层)

数据访问对象: java对于数据的操作进行统一的封装归类。

DAO类:在java程序中有一些特定的类专注于对于数据库的访问和操作!

1、现有的JDBC操作还停留在Test测试类或者main函数中。 如何去使用代码?

2、需要将代码进行封装 —> 封装成方法。 包含JDBC操作方法的类称之为DAO类

​ DAO的核心: java程序进行数据访问

3、DAO = DAO接口 + DAO的实现类

​ 好处: 3.1、 接口是规范

​ 3.2、 接口解耦合 使用和实现分离

​ 现阶段DAO实现类使用最为原始的JDBC技术进行开发,后续可能存在技术的升级

​ 使用全新的技术完成接口的实现,对于使用者来说没有任何的影响。

4、一个程序中实体类数量以及接口数量和实现类数量由什么决定?

​ 表 和 实体类 一 一 对应关系

​ 接口数量 也和 实体类 和 表 (建议最好 一 一 对应)

​ t_user表 —> User实体类

​ ----> UserDAO 接口 (一般会将对于一张表的所有操作定义在一个接口中)

在这里插入图片描述

    完成DAO类的开发
        中心思想:java程序区访问和操作数据库
    1、建表
    2、实体类对象
    3、根据CRUD需求定义接口中的方法
    4、使用JDBC技术去实现接口
    
    
    需求: 完成对于t_user表中数据的操作
   t_user 要求 列:  id(integer)  name(varchar2)  age(number)   birthday(date)
   1.根据名称查询用户数据
   2.根据id删除数据
   3.向表中添加数据
   4.修改用户数据的name 和 age 
   5.查询所有数据
   
   存在日期类型的数据 思路!
    //实体类的set、get方法中完成数据类型的转换
    //封装 类属性  赋值权/控制权   
    public java.sql.Date getBirthday() {
		return new java.sql.Date(birthday.getTime());
	}
	public void setBirthday(String birthday) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		try {
			Date date = sdf.parse(birthday);
			this.birthday = date;
		} catch (ParseException e) {
			e.printStackTrace();
		}	
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

八、Service业务 (层)

业务:用户的需求和项目的功能,对于现有程序中一个或者多个DAO中一个或多个方法的调用

​ 业务 : 接口 + 实现

在这里插入图片描述

需求分析的探讨:
	业务的方法 --->  业务接口  ----> DAO的接口 ---->   抽象出表和实体类

业务开发步骤
        中心思想:java程序区访问和操作数据库
    1、建表
    2、实体类对象
    3、根据CRUD需求定义接口中的方法
    4、使用JDBC技术去实现接口
    5、定义业务接口 service
    6、完成业务的接口实现   

需求:转账

UserService 接口

​ boolean transfer(User u1,User u2);

UserDAO接口

​ User queryUser (String username);

​ void updateUser(User user);

实体类 / 表 User t_user (ID,username,password ,account)

九、事务

业务操作中多条DML操作语句要么一起彻底成功要么一起彻底的失败。

JDBC技术默认自动commit提交!!!!

​ 关闭JDBC的默认提交策略,改为手动事务控制。

JDBC的事务控制 依赖于连接对象。 connection对象
	//关闭JDBC默认自动提交方式
	connection.setAutoCommit(false);
	//手动提交
	connection.commit();
	//手动回滚
	connection.rollback();

问题1?

​ Service中发生了异常,但是数据并没有回滚?

​ Service和DAO中的连接对象并不是同一个.

问题2?

​ 如何保证Service和DAO可以获取同一个连接对象?

​ 1、使用成员变量将连接对象进行传递. -----> 造成接口污染 X

​ JDBC技术中对于事务的控制使用连接对象Connection,

​ MyBatis技术中对于事务的控制使用连接对象sqlSession。

​ 2、final修饰

​ 数据库不可能只有一个人在用

线程绑定

当用户进行数据访问操作时,会在当前线程中绑定唯一的连接对象。

ThreadLocal线程绑定
        第一次创建连接对象后将对象存入线程中使用 set 方法。 
        之后再使用连接对象 通过 get 方法获取。

        代码写在什么地方??  用户通过工具类获取连接的时候进行判断
        
        当关闭资源的时候说明连接已经使用完毕,解除连接和线程的绑定。
        tl.remove();
工具类中 getConnection方法中

private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
	
//连接的绑定
public static Connection getConnection()
    throws ClassNotFoundException,SQLException{	
    //每一次获取连接对象都是通过  getConnection 方法 调用时需要进行判断当前是第几次获取连	
    //当前线程是否存在连接对象
    Connection conn = tl.get();
    if(conn == null){
        //第一次创建连接
        Class.forName(properties.getProperty("driver"));
        conn = DriverManager.getConnection(properties.getProperty("url"),
              properties.getProperty("username"), properties.getProperty("password"));
        //将创建出来的连接和当前线程绑定
        tl.set(conn);
        return conn;
    }
    //直接return 则说明线程中已经存在了连接对象
    return conn;
}
	
//关闭资源的时候需要解除1线程的绑定   tl.remove();
public static void close(Connection conn,PreparedStatement ps){
		if(ps!=null)try {ps.close();} catch (Exception e2) {}
		if(conn!=null)try {conn.close();tl.remove();} catch (Exception e2) {}
}

DAO中以后不再会关闭连接对象,Service中关闭连接对象。

注意:
	1、DAO中不能关闭连接对象
	2、最差情况:DAO中DML操作需要在catch块中完成手动的异常上抛
		或者所有的方法全抛异常
  return conn;
}
//直接return 则说明线程中已经存在了连接对象
return conn;

}

//关闭资源的时候需要解除1线程的绑定 tl.remove();
public static void close(Connection conn,PreparedStatement ps){
if(ps!=null)try {ps.close();} catch (Exception e2) {}
if(conn!=null)try {conn.close();tl.remove();} catch (Exception e2) {}
}

DAO中以后不再会关闭连接对象,Service中关闭连接对象。

注意:
1、DAO中不能关闭连接对象
2、最差情况:DAO中DML操作需要在catch块中完成手动的异常上抛
或者所有的方法全抛异常
#例子代码
1.工具类代码

public class JDBCUtil {
	private static Properties properties=new Properties();
	private static ThreadLocal<Connection> tl= new ThreadLocal<Connection>();
	static{
		InputStream is=JDBCUtil.class.getResourceAsStream("/util/jdbc.properties");
		try {
			properties.load(is);
			is.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//注册驱动类
	public static Connection getConnection() throws Exception{
		Connection con=tl.get();
		if(con==null){
			Class.forName(properties.getProperty("driver"));
			con=DriverManager.getConnection(properties.getProperty("url"),
											properties.getProperty("username"),
											properties.getProperty("password")
											);
			tl.set(con);
		}
		return con;
	}
	//关闭资源
	public static void close(PreparedStatement ps){
		if(ps!=null)try{ps.close();}catch(Exception e){}
	}
	public static void close(PreparedStatement ps,ResultSet rs){
		if(rs!=null)try{rs.close();}catch(Exception e){}
		if(ps!=null)try{ps.close();}catch(Exception e){}
	}
	public static void close(Connection con){
		if(con!=null)try{con.close();}catch(Exception e){}
	}
}

2.DAO层实现类

public class ProductDAOImpl implements ProductDAO {

	@Override
	public List<Product> queryAllProdut() {
		Connection con=null;
		PreparedStatement ps=null;
		List<Product> arrl = new ArrayList<Product>();
		ResultSet rs=null;
		try{
			con=JDBCUtil.getConnection();
			String sql="select * from product";
			ps=con.prepareStatement(sql);
			rs=ps.executeQuery();
			while(rs.next()){
				Product product= new Product();
				product.setId(rs.getInt("pro_id"));
				product.setName(rs.getString("pro_name"));
				product.setPrice(rs.getDouble("pro_price"));
				product.setDate(rs.getDate("hire_date"));
				arrl.add(product);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtil.close(ps, rs);
		}
		return arrl;
	}

	@Override
	public Product queryByName(String name) {
		Connection con=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		Product product=null;
		String likename="%"+name+"%";
		try{
			con=JDBCUtil.getConnection();
			String sql="select * from product where pro_name like ?";
			ps=con.prepareStatement(sql);
			ps.setString(1, likename);
			rs=ps.executeQuery();
			if(rs.next()){
				product= new Product();
				product.setId(rs.getInt("pro_id"));
				product.setName(rs.getString("pro_name"));
				product.setPrice(rs.getDouble("pro_price"));
				product.setDate(rs.getDate("hire_date"));
			}
			return product;
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}finally{
			JDBCUtil.close(ps, rs);
		}
		
	}

	@Override
	public void insertProduct(Product pro) {
		Connection con= null;
		PreparedStatement ps = null;
		try{
			con=JDBCUtil.getConnection();
			String sql="insert into product values(?,?,?,?)";
			ps=con.prepareStatement(sql);
			ps.setInt(1, pro.getId());
			ps.setString(2, pro.getName());
			ps.setDouble(3, pro.getPrice());
			ps.setDate(4, (java.sql.Date)pro.getDate());
			ps.executeUpdate();
		}catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException("修改操作出错");
		}finally{
			JDBCUtil.close(ps);
		}
	}

	@Override
	public void updateProductDate(String name) {
		Connection con =null;
		PreparedStatement ps=null;
		try{
			con=JDBCUtil.getConnection();
			String sql="update product set hire_date = sysdate where pro_name=?";
			ps=con.prepareStatement(sql);
			ps.setString(1,name);
			ps.executeUpdate();
		}catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException("修改日期出现错误");
		}finally{
			JDBCUtil.close(ps);
		}
	}

}

3.service层实现类

public class ProductServiceImpl implements ProductService {
	ProductDAOImpl pdi = new ProductDAOImpl();
	@Override
	public List<Product> queryAll() {
		List l =pdi.queryAllProdut();
		return l;
	}

	@Override
	public Product queryName(String name) {
		Product product = pdi.queryByName(name);
		return product;
	}
	/*完成商品的添加入库 (如果名称重复,修改hire_date为当前时间)
			1、查询商品名称
	     	2、不存在 数据添加
		 	3、存在 修改 hire_date 为系统当前时间*/
	@Override
	public boolean insert(Product product) {
		Connection con=null;
		try{
			con=JDBCUtil.getConnection();
			con.setAutoCommit(false);
			Product queryResult = pdi.queryByName(product.getName());
			if(queryResult != null){
				pdi.updateProductDate(product.getName());
			}else{
				pdi.insertProduct(product);
			}
			con.commit();
			return true;
		}catch(Exception e ){
			e.printStackTrace();
			if(con!=null)try {con.rollback();} catch (SQLException e1) {e1.printStackTrace();}
			return false;
		}finally{
			JDBCUtil.close(con);
		}
	}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值