JDBC笔记

server/2025/2/8 20:32:26/

简介

JDBC简单执行过程:

总结Java提供接口;数据库厂商提供实现;程序员调用接口;接口调用实现类,连接操作数据库

 JDBC的概念

 JDBC是Java提供的一组独立于任何数据库管理系统的API。

java操作数据库

步骤:

1 注册驱动(将数据库厂商得驱动类通过类加载得方式加载到程序中)

JDK6开始,不再需要显式地调用 `Class.forName()` 来加载 JDBC 驱动程序,只要在类路径中集成了对应的jar文件,会自动在初始化时注册驱动程序。

2 通过DriverManager调用getConnection()传入主机地址端口号要使用得数据库,用户名,用户密码---------以此来获得一个连接对象

 Connection接口是JDBC API的重要接口,用于建立与数据库的通信通道

 在建立连接时,需要指定数据库URL、用户名、密码参数。

3 通过connection对象调用createStatement()方法获得statement对象(是发送SQL语句的对象)

`Statement` 接口用于执行 SQL 语句并与数据库进行交互可以向数据库发送 SQL 语句并获取执行结果。

PreparedStatement(处理SQL注入攻击问题)

防止SQL注入:`PreparedStatement` 支持参数化查询,将数据作为参数传递到SQL语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来'',无论传递什么都作为值。有效防止传入关键字或值导致SQL注入问题。

4 编写SQL语句(语法与在Mysql中写的一样)

5 通过statement调用executeQuery()方法,传入SQL语句-----------依次获得resultSet(结果集)

            MySQL中查询的结果被封装在resultSet中,resultSet中有行和列的数据存储

6 通过resultSet调用getXXX()方法获得数据

            查询结果中该列的数据是什么类型的就调用  get该类型()----------可通过列名也可通过索引获取函数

7 关闭资源    connection连接对象   statement传输对象     resultSet结果集

实体类搭建与ORM封装对象

实体类和ORM

> - 在使用JDBC操作数据库时,我们会发现数据都是零散的,明明在数据库中是一行完整的数据,到了Java中变成了一个一个的变量,不利于维护和管理。而我们Java是面向对象的,一个表对应的是一个类,一行数据就对应的是Java中的一个对象,一个列对应的是对象的属性,所以我们要把数据存储在一个载体里,这个载体就是实体类!

> - ORM(Object Relational Mapping)思想,**对象到关系数据库的映射**,作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来,以面向对象的角度操作数据库中的数据即一张表对应一个类,一行数据对应一个对象,一个列对应一个属性!

例如将下面的表封装为一个个对象

   /*ORM封装多个对象:*创建一个数组将封装好的对象放入数组中;* 在循环中创建一个对象,下一次循环会将改对象覆盖掉,所以在依次循环的最后要赋值完毕的对象保存在集合中*/@Testpublic void testORMList() throws SQLException {Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "abc123LQ");PreparedStatement preparedStatement = connection.prepareStatement("SELECT emp_id,emp_name,emp_salary,emp_age FROM t_emp");ResultSet resultSet = preparedStatement.executeQuery();Employee employee=null;//将多个对象保存在集合中;List<Employee> employeeList=new ArrayList<>();while(resultSet.next()){employee=new Employee();//下一次循环会将改对象覆盖掉,所以在依次循环的最后要赋值完毕的对象保存在集合中int emp_id = resultSet.getInt("emp_id");String emp_name = resultSet.getString("emp_name");double emp_salary = resultSet.getDouble("emp_salary");int emp_age = resultSet.getInt("emp_age");//为对象属性赋值employee.setEmpId(emp_id);employee.setEmpName(emp_name);employee.setEmpSalary(emp_salary);employee.setEmpAge(emp_age);//将每次循环的一行数据对象存储在集合里employeeList.add(employee);}//遍历集合for (Employee employee1 : employeeList) {System.out.println(employee1);}//资源释放resultSet.close();preparedStatement.close();connection.close();}

主键回显

- 在数据中,执行新增操作时,主键列为自动增长,可以在表中直观的看到,但是在Java程序中,我们执行完新增后,只能得到受影响行数,无法得知当前新增数据的主键值。在Java程序中获取数据库中插入新数据后的主键值,并赋值给Java对象,此操作为主键回显。

批量操作

 插入多条数据时,一条一条发送给数据库执行,效率低下!

 通过批量操作,可以提升多次操作效率!

    批量操作

    Java默认连接Mysql是无法进行皮量操作的

    步骤:1 必须在连接数据库的URL后追加?rewriteBatchedStatements=true

          将jdbc:mysql:///atguigu改为jdbc:mysql:///atguigu?rewriteBatchedStatements=true

         2 新增SQL必须用values,且语句最后不要追加;结束

         3 通过prepareStatement调用addBatch()方法-------------将SQL语句进行批量添加操作

         4 通过prepareStatement调用executeBatch()方法---------------------统一执行批量操作

连接池

 现有问题

> - 每次操作数据库都要获取新连接,使用完毕后就close释放,频繁的创建和销毁造成资源浪费。

> - 连接的数量无法把控,对服务器来说压力巨大。

连接池

> 连接池就是数据库连接对象的缓冲区,通过配置,由连接池负责创建连接、管理连接、释放连接等操作。

> 预先创建数据库连接放入连接池,用户在请求时,通过池直接获取连接,使用完毕后,将连接放回池中,避免了频繁的创建和销毁,同时解决了创建的效率。

> 当池中无连接可用,且未达到上限时,连接池会新建连接。

> 池中连接达到上限,用户请求会等待,可以设置超时时间。

    Druid软编码实现

    1 创建Properties集合,用于存储外部配置文件的key与value值

           创建Properties对象

    2 读取外部配置文件,获取输入流,加载到properties集合里

           加载类时,创建输入流

           类加载;类名.class.getClassLoader()

           创建输入流:在类加载后调用getResourceAsStream()方法,出入要读取的文件路径

        加载到properties集合里:通过properties调用load()方法

    3 基于properties集合构建DruidDataSource连接池

          通过DruidDataSourceFactory调用createDataSource()方法,出入已读取好文件的properties对象-----------获得连接池(dataSource)

    4 通过连接池获取连接对象

           通过dataSource连接池调用getConnection()-----------------获得连接对象

代码

    @Testpublic void testResourcesDruid() throws Exception {//1 创建Properties集合,用于存储外部配置文件的key与value值Properties properties=new Properties();//2 读取外部配置文件,获取输入流,加载到properties集合里、InputStream inputStream = DruidTest.class.getClassLoader().getResourceAsStream("db.properties");/*加载类时,创建输入流*/properties.load(inputStream);//3 基于properties集合构建DruidDataSource连接池DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);//4 通过连接池获取连接对象Connection connection = dataSource.getConnection();//5 开发CRUDSystem.out.println(connection);//6 回收连接connection.close();}

HikariCP编码实现  

    1 创建Properties集合,用于存储外部配置文件的keyvalue--------------通过Properties构造器创建properties对象

    2 读取外部配置文件,获取输入流,加载到properties集合里

           加载类时,创建输入流

           类加载;类名.class.getClassLoader()

           创建输入流:在类加载后调用getResourceAsStream()方法,出入要读取的文件路径

        加载到properties集合里:通过properties调用load()方法

    3 创建HikariConfig连接池配置对象,将properties集合传进去

             通过HikariConfig构造器创建连接池配置对象,传入properties

    4 基于HikariConfig连接池配置对象,构建HikariDataSource

            通过调用HikariDataSource的构造器,传入HikariConfig创建连接池

    5 通过连接池获取连接对象

            通过HikariDataSource的对象调用getConnection()方法

    @Testpublic void testResourcesHikari() throws IOException, SQLException {//1 创建Properties集合,用于存储外部配置文件的key与value值Properties properties=new Properties();//2 读取外部配置文件,获取输入流,加载到properties集合里InputStream InputStream = HikariTest.class.getClassLoader().getResourceAsStream("hikari.properties");properties.load(InputStream);//3 创建HikariConfig连接池配置对象,将properties集合传进去HikariConfig hikariConfig=new HikariConfig(properties);//4 基于HikariConfig连接池配置对象,构建HikariDataSourceHikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);Connection connection = hikariDataSource.getConnection();//5 获取连接System.out.println(connection);//6 回收连接connection.close();}

工具类:

JDBC优化及工具类封装

 现有问题

> 我们在使用JDBC的过程中,发现部分代码存在冗余的问题:

> - 创建连接池。

> - 获取连接。

> - 连接的回收。

JDBC工具类

     1 维护连接池对象(该连接池在整个项目中都可以使用);维护了一个线程绑定变量的ThreadLocal对象

              在本地线程里存一个连接对象,此值可以在当前项目中任何位置都可以拿到----------在一个项目中使用的是同一个连接对象

     2 对外提供在ThreadLocal中获取连接的方法

     3 对外提供收回连接的方法,回收过程中,将要回收的连接从ThreadLocal中移除

 注意:工具类仅对外提供共性的功能代码,所以方法均为静态方法

      使用ThreadLocal就是为了一个线程在对此数据库操作过程中。使用的是同一个连接

代码:

public class JDBCUtil2 {//创建连接池引用,因为要提供为当前项目的全全局使用,所以创建为静态的private static DataSource dataSource;private static ThreadLocal<Connection> threadLocal=new ThreadLocal<>();//在项目启动时即创建连接池对象,并赋值给dataSource(使用静态代码块:静态类型的属性在静态代码块中赋值)static {try {Properties properties = new Properties();InputStream InputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");properties.load(InputStream);//静态代码块是不能向外声明异常的dataSource = DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {throw new RuntimeException(e);}}//-------------------------------------------------------------------维护连接池对象(该连接池在整个项目中都可以使用)public static Connection getConnection(){try {//在ThreadLocal中获取ConnectionConnection connection = threadLocal.get();if(connection==null){//threadLocal中没有存储Connection,也就是第一次获取//在连接池中获取一个连接,存储在threaLocal里connection = dataSource.getConnection();threadLocal.set(connection);}return connection;} catch (SQLException e) {throw new RuntimeException(e);}}//-------------------------------------------------------------------对外提供在连接池中获取连接的方法public static void release(){try {Connection connection = threadLocal.get();if(connection!=null){//从threaLocal中移除当前已经存储的connection对象threadLocal.remove();//如果开启了事务的手动提交,提交操作完毕后,还给连接池之前要将事务的手动提交改为trueconnection.setAutoCommit(true);---------------------------------事务//将connection对象归还连接池connection.close();}} catch (SQLException e) {throw new RuntimeException(e);}}//-------------------------------------------------------------------对外提供收回连接的方法
}

DAO概念及搭建

DAO:Data Access Object,数据访问对象。

> Java是面向对象语言,数据在Java中通常以对象的形式存在。一张表对应一个实体类,一张表的操作对应一个DAO对象!

> Java操作数据库时,我们会将对同一张表的增删改查操作统一维护起来,维护的这个类就是DAO

> DAO层只关注对数据库的操作,供业务层Service调用,将职责划分清楚!

 BaseDAO概念

> 基本上每一个数据表都应该有一个对应的DAO接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以可以抽取公共代码给这些DAO的实现类可以抽取一个公共的父类,复用增删改查的基本操作,我们称为BaseDAO。

代码及思路:

{/*** 通用的增删改方法* @param sql  调用者要执行的sql语句* @param params  SQL语句中占位符要赋值的参数* @return  返回受影响的行数*/public int executeUpdate(String sql,Object... params) throws Exception {//1 通过JDBCUtil2获取数据库连接Connection connection = JDBCUtil2.getConnection();//2 预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);//3 为占位符赋值if(params!=null && params.length>0){//防止没有为占位符输入要赋值的参数for(int i=0;i<params.length;i++){//占位符是从以开始的,参数的数组是从0开始的preparedStatement.setObject(i+1,params[i]);}}int row = preparedStatement.executeUpdate();//5 释放资源(要在返回值前释放)preparedStatement.close();if(connection.getAutoCommit()){JDBCUtil2.release();}//4 返回结果return row;}//BaseDAO搭建通用查询方法/*思路:通用的查询:多行多列,单行多列,单行单列多行多列 List<T>单行多列 对象单行单列 封装的是一个结果 ,Double Integer....封装过程:1 返回的类型:泛型:类型不确定,调用者知道;调用时,将此次查询的结果类型告知BaseDAO就可以了2 返回的结果:通用,List  可以存储多个结果,也可以存储单个结果 get(0)3 结果的封装:反射,要求调用者告知BaseDAO要封装对象的类对象*/public <T> List<T> executeQuery(Class<T> clazz,String sql,Object... params) throws Exception {Connection connection = JDBCUtil2.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql);if(params!=null&&params.length>0){for(int i=0;i<params.length;i++){preparedStatement.setObject(i+1,params[i]);}}ResultSet resultSet = preparedStatement.executeQuery();//获取结果集中元数据对象------------------------------将查询结果的整张表看成一个对象//包含了列的数量,每个列的名称ResultSetMetaData metaData = preparedStatement.getMetaData();//列数int columnCount = metaData.getColumnCount();List<T> list=new ArrayList<>();//处理结果while (resultSet.next()){//循环一次,代表有一行数据,就创建一个对象将其存储起来//通过反射创建对象T t=clazz.newInstance();//通过循环遍历当前行的列,获取每一列的数据for(int i=1;i<=columnCount;i++){//通过下标获取列的值,获取到的列的value值,这个值就是t这个对象中的某一属性的值Object value = resultSet.getObject(i);//获取当前拿到的列的名字=对象的属性名String filedName = metaData.getColumnLabel(i);//通过类的对象和filedName获取要粉装的对象的属性Field field = clazz.getDeclaredField(filedName);//突破封装的privatefield.setAccessible(true);field.set(t,value);}list.add(t);}resultSet.close();preparedStatement.close();if(connection.getAutoCommit()){JDBCUtil2.release();}return list;
}//通用的查询单个结果方法
/*** 通用查询:在上面查询的集合结果中获取第一个结果简化了单行单列的获取,也简化了单行多列的获取*/public <T> T executeQueryBean(Class<T> clazz,String sql,Object... params) throws Exception{List<T> list = this.executeQuery(clazz,sql,params);if(list==null || list.size()==0){return null;}return list.get(0);}}

事务

- 数据库事务就是一种SQL语句执行的缓存机制,不会单条执行完毕就更新数据库数据,最终根据缓存内的多条语句执行结果统一判定!   一个事务内所有语句都成功及事务成功,我们可以触发commit提交事务来结束事务,更新数据!   一个事务内任意一条语句失败,即为事务失败,我们可以触发rollback回滚结束事务,数据回到事务之前状态! 

- 事务的特性:

  1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,  要么都不发生。

  2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

  3. 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,  即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

  4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,  接下来的其他操作和数据库故障不应该对其有任何影响

- 事务的提交方式:

  - 自动提交:每条语句自动存储一个事务中,执行成功自动提交,执行失败自动回滚!

  - 手动提交:  手动开启事务,添加语句,手动提交或者手动回滚即可!

注意点:当开启事务后,切记一定要根据代码执行结果来决定是否提交或回滚!否则数据库看不到数据的操作结果


http://www.ppmy.cn/server/166023.html

相关文章

一键掌握多平台短视频矩阵营销/源码部署

短视频矩阵系统的介绍与应用 随着数字化营销策略的不断演进&#xff0c;传统的短视频矩阵操作方法可能已显陈旧。为此&#xff0c;一款全新的短视频矩阵系统应运而生&#xff0c;它通过整合多个社交媒体账户、创建多样化的任务、运用先进的智能视频编辑工具、实现多平台内容的…

如何使用 Excel 进行多元回归分析?

多元回归分析&#xff0c;一种统计方法&#xff0c;用来探索一个因变量&#xff08;即结果变量&#xff09;与多个自变量&#xff08;即预测变量&#xff09;之间的关系。广泛用于预测、趋势分析以及因果关系的分析。 听起来这个方法很复杂&#xff0c;但其实在 Excel 中可以很…

Docker镜像管理:掌握save/load与export/import的精髓

0x01 Docker Save & Load docker save: 用于将Docker镜像保存为.tar文件。这个过程会保存镜像的所有层、元数据和历史记录&#xff0c;因此生成的文件较大。当你需要备份或者迁移某个镜像时非常有用&#xff0c;尤其是当你需要保留镜像的全部构建历史以便将来在其他地方恢复…

在 Ubuntu 22.04 上运行 Filebeat 7.10.2

环境 操作系统&#xff1a;阿里云 Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-83-generic x86_64) 软件版本&#xff1a;Filebeat 7.10.2 用户&#xff1a;root 运行 下载 从这里下载 filebeat 7.10.2。 配置 简单配置一下 filebeat.yml&#xff0c;从标准输入采集&#xf…

Vue(4)

一.组件的三大组成部分-注意点说明 &#xff08;1&#xff09;scoped样式冲突 默认情况&#xff1a;写在组件中的样式会全局生效 → 因此很容易造成多个组件之间的样式冲突 ①全局样式&#xff1a;默认组件中的样式会作用到全局 ②局部样式&#xff1a;可以给组件加上scoped属…

深度学习与搜索引擎优化的结合:DeepSeek的创新与探索

目录 引言 1. 传统搜索引擎的局限性 2. 深度学习在搜索引擎中的作用 3. DeepSeek 实现搜索引擎优化的关键技术 3.1 神经网络与搜索引擎优化 3.2 自然语言处理与查询理解 3.3 深度强化学习与搜索结果排序 4. DeepSeek的深度学习架构 4.1 查询解析与语义理解 4.2 搜索排名与相…

【数据安全】现代智能手机的数据加密机制

这两天刷抖音看到一个降智视频&#xff0c;说手机拿去修了明明没给他密码&#xff0c;但是他是怎么导出手机的数据呢&#xff0c;而且很多人看你都会有这样的疑问&#xff1a;“我的手机设有锁屏密码数据真的安全吗&#xff1f;锁屏密码存在意义是不是仅限于防止别人进入桌面这…

业务架构、数据架构、应用架构和技术架构

TOGAF(The Open Group Architecture Framework)是一个广泛应用的企业架构框架&#xff0c;旨在帮助组织高效地进行架构设计和管理。 TOGAF 的核心就是由我们熟知的四大架构领域组成:业务架构、数据架构、应用架构和技术架构。 企业数字化架构设计中的最常见要素是4A 架构。 4…