JDBC笔记

简介

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.rhkb.cn/news/14292.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全威胁框架与入侵分析模型概述

引言 “网络安全攻防的本质是人与人之间的对抗&#xff0c;每一次入侵背后都有一个实体&#xff08;个人或组织&#xff09;”。这一经典观点概括了网络攻防的深层本质。无论是APT&#xff08;高级持续性威胁&#xff09;攻击、零日漏洞利用&#xff0c;还是简单的钓鱼攻击&am…

FPGA|生成jic文件固化程序到flash

1、单击file-》convert programming files 2、flie type中选中jic文件&#xff0c;configuration decive里根据自己的硬件选择&#xff0c;单击flash loader选择右边的add device选项 3、选择自己的硬件&#xff0c;单击ok 4、选中sof选项&#xff0c;单机右侧的add file 5、选…

P3654 First Step (ファーストステップ)(贪心算法)

#include<bits/stdc.h> using namespace std;int main() {int r,c,k;cin>>r>>c>>k;char a[105][105];int ans0;for(int i0;i<r;i){for(int j0;j<c;j){cin>>a[i][j];}}for(int i0;i<r;i){int cnt0; // 用来记录连续空地的数量for(int j…

Java/Kotlin双语革命性ORM框架Jimmer(一)——介绍与简单使用

概览 Jimmer是一个Java/Kotlin双语框架 包含一个革命性的ORM 以此ORM为基础打造了一套综合性方案解决方案&#xff0c;包括 DTO语言 更全面更强大的缓存机制&#xff0c;以及高度自动化的缓存一致性 更强大客户端文档和代码生成能力&#xff0c;包括Jimmer独创的远程异常 …

ASP.NET Core中Filter与Middleware的区别

中间件是ASP.NET Core这个基础提供的功能&#xff0c;而Filter是ASP.NET Core MVC中提供的功能。ASP.NET Core MVC是由MVC中间件提供的框架&#xff0c;而Filter属于MVC中间件提供的功能。 区别 中间件可以处理所有的请求&#xff0c;而Filter只能处理对控制器的请求&#x…

ASP.NET Core对JWT的封装

目录 JWT封装 [Authorize]的注意事项 JWT封装 NuGet 库 |Microsoft.AspNetCore.Authentication.JwtBearer 9.0.1https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearerhttps://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBea…

【Uniapp-Vue3】从uniCloud中获取数据

需要先获取数据库对象&#xff1a; let db uniCloud.database(); 获取数据库中数据的方法&#xff1a; db.collection("数据表名称").get(); 所以就可以得到下面的这个模板&#xff1a; let 函数名 async () > { let res await db.collection("数据表名称…

腾讯云TI平台×DeepSeek:开启AI超强体验,解锁部署秘籍

引言 在人工智能飞速发展的今天&#xff0c;AI技术的应用场景已经渗透到我们生活的方方面面。从智能客服到自动驾驶&#xff0c;从精准医疗到金融科技&#xff0c;AI的应用正在不断推动各行业的变革与创新。作为AI领域的领军企业&#xff0c;腾讯云一直以来都在致力于为开发者…

利用 IMU 估计人体关节轴向和位置 —— 论文推导

Title: 利用 IMU 估计人体关节轴向和位置 —— “Joint axis and position estimation from inertial measurement data by exploiting kinematic constraints” —— 论文推导 文章目录 I. 论文回顾II. 铰接关节的约束1. 铰接关节约束的原理2. 铰接关节约束的梯度3. 铰接关节约…

pushgateway指标聚合问题

一 问题现象 一个job有多个实例推送指标&#xff0c;但是从pushgateway上看这个job的instance字段&#xff0c;只显示一个实例的ip&#xff0c;而不是多个实例。导致在grafana上无法正常根据ip查看监控。 应用的prometheus的配置 management:metrics:tags:application: ${spr…

无界构建微前端?NO!NO!NO!多系统融合思路!

文章目录 微前端理解1、微前端概念2、微前端特性3、微前端方案a、iframeb、qiankun --> 使用比较复杂 --> 自己写对vite的插件c、micro-app --> 京东开发 --> 对vite支持更拉跨d、EMP 方案--> 必须使用 webpack5 --> 很多人感觉不是微前端 --> 去中心化方…

Vim 多窗口编辑及文件对比

水平分割 :split 默认使用水平分割的方式。 :split :sp 垂直分割 :vsplit :vs 带文件的分割 :split 文件名 :sp 文件名 在光标所在的窗口&#xff0c;输入分割窗口命令就会对那个窗口进行分割。 切换窗口 Ctrlw 切换正在编辑的窗口 快速分割窗口 Ctrlwn 快速分割当前…

yolov11模型在Android设备上运行【踩坑记录】

0) 参考资料: https://github.com/Tencent/ncnn?tabreadme-ov-file https://github.com/pnnx/pnnx https://github.com/nihui/ncnn-android-yolov5 https://github.com/Tencent/ncnn?tabreadme-ov-file 1) &#xff1a;将xxx.pt模型转化成 xxx.onnx ONNX&#xff08;Ope…

电商平台的设计与实现(代码+数据库+LW)

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统商品交易信息管理难度大&#xff0c;容错率低&#xff0…

学习笔记:机器学习中的数学原理(一)

1. 集合 集合分为有限集和无限集&#xff1b; 对于有限集&#xff0c;两集合元素数相等即为等势&#xff1b; 对于无限集&#xff0c;两集合元素存在一一映射关系即为等势&#xff1b; 无限集根据是否与正整数集等势分为可数集和不可数集。 2. sigmoid函数&#xff08;也叫…

【翻译+论文阅读】DeepSeek-R1评测:粉碎GPT-4和Claude 3.5的开源AI革命

目录 一、DeepSeek-R1 势不可挡二、DeepSeek-R1 卓越之处三、DeepSeek-R1 创新设计四、DeepSeek-R1 进化之路1. 强化学习RL代替监督微调学习SFL2. Aha Moment “啊哈”时刻3. 蒸馏版本仅采用SFT4. 未来研究计划 部分内容有拓展&#xff0c;部分内容有删除&#xff0c;与原文会有…

互联网分布式ID解决方案

业界实现方案 1. 基于UUID 2. 基于DB数据库多种模式(自增主键、segment) 3. 基于Redis 4. 基于ZK、ETCD 5. 基于SnowFlake 6. 美团Leaf(DB-Segment、zkSnowFlake) 7. 百度uid-generator() 基于UUID生成唯一ID UUID生成策略 推荐阅读 DDD领域驱动与微服务架构设计设计模…

使用Python实现PDF与SVG相互转换

目录 使用工具 使用Python将SVG转换为PDF 使用Python将SVG添加到现有PDF中 使用Python将PDF转换为SVG 使用Python将PDF的特定页面转换为SVG SVG&#xff08;可缩放矢量图形&#xff09;和PDF&#xff08;便携式文档格式&#xff09;是两种常见且广泛使用的文件格式。SVG是…

CV(11)-图像分割

前言 仅记录学习过程&#xff0c;有问题欢迎讨论 图像分割 语义分割不需要区分具体的个体&#xff0c;实例分割需要 反卷积/转置卷积&#xff1a; 它并不是正向卷积的完全逆过程。反卷积是一种特殊的正向卷积&#xff0c;先按照一定的比例通过补0 来扩大输入图像的尺寸&…

封装descriptions组件,描述,灵活

效果 1、组件1&#xff0c;dade-descriptions.vue <template><table><tbody><slot></slot></tbody> </table> </template><script> </script><style scoped>table {width: 100%;border-collapse: coll…