后端学习 - JDBC

文章目录

  • 一 JDBC概述
    • 1 Java中的数据存储技术
    • 2 什么是JDBC
    • 3 JDBC程序的编写步骤
  • 二 Java连接数据库的方式
  • 三 使用 PreparedStatement 实现 CRUD 操作
    • 1 数据库的调用的三个接口
    • 2 增Create/删Delete/改Update 操作
    • 3 查Retrieval操作
    • 4 批量插入操作
  • 四 数据库事务
    • 1 事务
    • 2 事务的 ACID 性质
    • 3 三种导致数据自动提交的操作
    • 4 MySQL 的四种隔离级别
    • 5 根据 ACID 改进实现
  • 五 DAO(Data Access Object) 逻辑架构
  • 六 数据库连接池
    • 1 作用
    • 2 C3P0 数据库连接池
    • 3 DBCP 数据库连接池
    • 4 Druid 数据库连接池(实用) *
  • 七 Apache-DBUtils 实现 CRUD 操作 *
    • 1 实现
    • 2 自定义 Handler
    • 3 资源的关闭

一 JDBC概述

1 Java中的数据存储技术

  • JDBC(Java Database Connectivity)直接访问数据库;
  • JDO(Java Data Object)技术;
  • 第三方工具,如Hibernate, Mybatis 等。

后两种本质上是更好地封装了JDBC。

2 什么是JDBC

独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,使用这些类库可以以一种标准的方法、方便地访问数据库资源。JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题
在这里插入图片描述

3 JDBC程序的编写步骤

在这里插入图片描述

二 Java连接数据库的方式

  • 一个数据库连接就是一个 socket 连接。socket = (IP : port)
  • 这种方式实现了数据与代码的分离,实现了解耦;如果需要修改配置文件信息,可以避免程序重新打包。
	public void getConnection5() throws Exception{//1.读取配置文件中的4个基本信息InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");//2.加载驱动,注释部分会自动运行Class clazz = Class.forName(driverClass);  //也可省略 Class clazz =//Driver driver = (Driver) clazz.newInstance();//DriverManager.registerDriver(driver);//3.获取连接Connection conn = DriverManager.getConnection(url, user, password);}

三 使用 PreparedStatement 实现 CRUD 操作

1 数据库的调用的三个接口

  • Statement(已淘汰):用于执行静态 SQL 语句并返回它所生成结果的对象;
  • PreparedStatement:SQL 语句被预编译并存储在此对象中(所以,一个 PreparedStatement 的实例表示一条预编译过的 SQL 语句),可以使用此对象多次高效地执行该语句,是Statement的子接口;
  • CallableStatement:用于执行 SQL 存储过程,是Statement的子接口。
    在这里插入图片描述

2 增Create/删Delete/改Update 操作

根据有无返回值,将增删改归为一类方法,查归为一类方法。

	/* 定义时 */public void commonOps(String sql, Object... args) {Connection conn = null;PreparedStatement ps = null;try {// 1.连接数据库,获得conn,并根据sql预加载psconn = JDBCUtils.getMyConnection();  // 自己封装的方法,实现同二部分ps = conn.prepareStatement(sql);  // PreparedStatement的特性:预编译sql语句// 2.填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);  // sql索引从1开始}// 3.执行ps.execute();} catch (Exception e) {e.printStackTrace();} finally {// 4.关闭资源JDBCUtils.closeMyResources(conn, ps);}}/* 使用时 */public void deleteTest() {String sql = "delete from customers where name = ?";String delete_name = "张三";commonOps(sql, delete_name);}

3 查Retrieval操作

  • ResultSet 的 next() ,执行两步操作:如果下一项不为空,返回 true,并将指针下移。(和 Iterator 的方法相比,相当于一起执行了 hasNext() 和 next()
  • ResultSetMetaData 用于获取查询结果 ResultSet 的元数据,在此获取的是表的 列数、列名。
  • 和 getColumnName() 相比,getColumnLabel() 避免了表名和属性名不统一,方便反射操作。如果表列名和属性名不一致,则在输入sql语句时需要将查询的别名设置为属性名
  • ORM object relational mapping思想:表的一行代表一个实例,表的一列代表一个属性。

执行步骤:

  1. 执行连接,获取预编译 sql 的对象 ps ;
  2. 填充 sql 语句的占位符,执行得到rs;
  3. 遍历 rs 的每一条记录,使用反射,为每条记录建立一个对象并填充对应属性值;
  4. 返回结果。
    public <T> List<T> allMultiResultCommonSelect(Class<T> clazz, String sql, Object... args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;List<T> result = new ArrayList<>();  // 返回结果try {conn = JDBCUtils.getMyConnection();ps = conn.prepareStatement(sql);for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}rs = ps.executeQuery();while (rs.next()) {// 获取元数据,以得到结果的列数ResultSetMetaData rsmd = rs.getMetaData();// 利用*反射*动态创建类T res = clazz.newInstance();int col = rsmd.getColumnCount();// 向customer中填入查询结果for (int i = 0; i < col; i++) {Object property_value = rs.getObject(i + 1);  // 获取当前属性的值String property_name = rsmd.getColumnLabel(i + 1);  // 和 getColumnName相比,getColumnLabel避免了表名和属性名不统一Field field = res.getClass().getDeclaredField(property_name);  // 使用反射更改属性值field.setAccessible(true);field.set(res, property_value);}result.add(res);}return result;} catch (Exception e) {e.printStackTrace();} finally {JDBCUtils.closeMyResources(conn, ps, rs);}return null;}

4 批量插入操作

使用了两个技巧:

  1. 批处理 sql :1.addBatch()、executeBatch()、clearBatch()。MySQL 服务器默认是关闭批处理的,将 rewriteBatchedStatements=true 写在配置文件的url后面以开启。
  2. 关闭自动提交,在所有的 sql 执行完之后统一提交。
	public void testInsert3() {Connection conn = null;PreparedStatement ps = null;try {conn = JDBCUtils.getConnection();//设置不允许自动提交数据conn.setAutoCommit(false);String sql = "insert into goods(name)values(?)";ps = conn.prepareStatement(sql);for(int i = 1;i <= 1000000;i++){ps.setObject(1, "name_" + i);//1.将一条sql加入到batchps.addBatch();if(i % 500 == 0){//2.执行batchps.executeBatch();//3.清空batchps.clearBatch();}}//提交数据conn.commit();} catch (Exception e) {	e.printStackTrace();}finally{JDBCUtils.closeResource(conn, ps);}}

四 数据库事务

1 事务

  • 事务是一组逻辑操作单元,使数据从一种状态变换到另一种状态。
  • 事务的操作要么全部执行,要么全不执行。

2 事务的 ACID 性质

  • 原子性(DBMS保证):事务的操作要么全部执行,要么全不执行。
  • 一致性(用户保证):如果事务的程序正确,并且事务启动时数据库处于一致状态,则事务结束时数据库也要处于一致状态。
  • 隔离性(DBMS保证):一个事务的执行不受其它事务的影响。
  • 持久性(DBMS保证):事务一旦提交,事务对数据库的修改一定全部持久地写到数据库中。

3 三种导致数据自动提交的操作

  • DDL(Data Definition Language) 操作一旦执行,都会自动提交。
  • DML(Data Manipulation Language) 默认情况下,一旦执行,就会自动提交。可以通过 conn.setAutoCommit(false) 的方式取消DML操作的自动提交。若此时 Connection 没有被关闭,还可能被重复使用,则需要恢复其自动提交状态 setAutoCommit(true)。尤其是在使用数据库连接池技术时,执行close()方法前,建议恢复自动提交状态。
  • 默认在关闭连接时自动提交。

4 MySQL 的四种隔离级别

  • READ UNCOMMITTED 读未提交:可能发生脏读、不可重复读、幻读;
  • READ COMMITTED 读提交:可能发生不可重复读、幻读;
  • REPEATABLE READ 可重复读:可能发生幻读;
  • SERIALIZABLE 串行化:不会发生以上情况,但效率极低。

幻读举例:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。

5 根据 ACID 改进实现

  • 执行前关闭 connection 的自动提交。
  • 在哪个方法创建的资源,在哪个方法关闭。
  • finally 块负责方法的关闭,事务的提交,以及恢复 connection 的自动提交。
  • catch 块负责 rollback。

五 DAO(Data Access Object) 逻辑架构

在这里插入图片描述

  • DAO 基类设置为泛型类,因为要供所有的表使用。
  • DAO 接口非泛型类,因为一张表对应一个接口,查询的返回对象类型是确定的。

六 数据库连接池

1 作用

  • 为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但没有关闭数据库的物理连接,仅仅把数据库连接释放,归还给数据库连接池。
  • 数据库连接池负责分配、管理和释放数据库连接,允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
  • 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中。通过限制最小和最大的连接数,保证数据库对连接数的控制。
  • 使用时,数据库连接池只需创建一个,其中的连接可以创建多个。创建数据库连接池可以用静态代码块进行初始化。

2 C3P0 数据库连接池

C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性较好。

使用 ComboPooledDataSource 类代替之前使用的 DriverManager 进行连接的获取。

    public void xmlTest () throws Exception {ComboPooledDataSource cpds = new ComboPooledDataSource("my_config");Connection conn = cpds.getConnection();}

其中 c3p0-config.xml 的内容如下(文件名不能更改)

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config><named-config name="my_config"><!-- 提供获取连接的4个基本信息 --><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql:///test</property><property name="user">root</property><property name="password">123</property><!-- 进行数据库连接池管理的基本信息 --><!-- 当数据库连接池中的连接数不够时,c3p0一次性向数据库服务器申请的连接数 --><property name="acquireIncrement">5</property><!-- c3p0数据库连接池中初始化时的连接数 --><property name="initialPoolSize">10</property><!-- c3p0数据库连接池维护的最少连接数 --><property name="minPoolSize">10</property><!-- c3p0数据库连接池维护的最多的连接数 --><property name="maxPoolSize">100</property><!-- c3p0数据库连接池最多维护的Statement的个数 --><property name="maxStatements">50</property><!-- 每个连接中可以最多使用的Statement的个数 --><property name="maxStatementsPerConnection">2</property></named-config>
</c3p0-config>

3 DBCP 数据库连接池

  • Tomcat 的连接池采用该连接池实现。
  • 速度相对C3P0较快,但存在 bug,不够稳定。
	@Testpublic void propertiesTest() throws Exception {/* 加载配置文件 */Properties properties = new Properties();// 获取输入流的方法1// FileInputStream is = new FileInputStream(new File("src/dbcp.properties"));// 方法2InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");properties.load(is);/* 创建连接池 */DataSource source = BasicDataSourceFactory.createDataSource(properties);/* 获取连接 */Connection conn = source.getConnection();}

4 Druid 数据库连接池(实用) *

    @Testpublic void getConnectionTest () throws Exception {/* 加载配置文件 */Properties properties = new Properties();InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");properties.load(is);/* 创建连接池 */DataSource source = DruidDataSourceFactory.createDataSource(properties);/* 获取连接 */Connection conn = source.getConnection();}

七 Apache-DBUtils 实现 CRUD 操作 *

1 实现

public class ApacheUtilsTest {// 初始化数据库连接池private static DataSource source;static {InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");Properties properties = new Properties();try {properties.load(is);ApacheUtilsTest.source = DruidDataSourceFactory.createDataSource(properties);} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}// 增删改@Testpublic void insertTest() throws SQLException {QueryRunner queryRunner = new QueryRunner();Connection conn = ApacheUtilsTest.source.getConnection();String sql = "insert into customers (name, email, birth) values (?, ?, ?)";int count = queryRunner.update(conn, sql, "伍佰", "500@gmail.com", "1966-08-08");System.out.println(count);conn.close();}// 查记录@Testpublic void selectTest() throws SQLException {QueryRunner queryRunner = new QueryRunner();Connection conn = ApacheUtilsTest.source.getConnection();String sql = "select name, email from customers where id > ?";/* 查询一条记录 */// ResultSetHandler 接口的一个实现类,用于封装表的一条记录// BeanHandler<Customer> beanHandler = new BeanHandler<>(Customer.class);// Customer customer = queryRunner.query(conn, sql, beanHandler, 19);/* 查询多条记录 */// ResultSetHandler 接口的一个实现类,用于封装表的多条记录,返回结果相应地使用 List<Customer> 类型BeanListHandler<Customer> beanListHandler = new BeanListHandler<>(Customer.class);List<Customer> customers = queryRunner.query(conn, sql, beanListHandler, 18);/** 查询多条记录还有 MapListHandler,将一条记录作为一个 Map,key 是列名,value 是列的具体值* 返回值类型是 List<Map<String, Object>>** 同理查询一条记录的 MapHandler 的返回值类型是 Map<String, Object>** 所以:xxHandler 代表查询的返回值类型是 xx ??* */System.out.println(customers);conn.close();}// 查特殊值:使用 ScalarHandler@Testpublic void selectScalarTest() throws SQLException{QueryRunner queryRunner = new QueryRunner();Connection conn = ApacheUtilsTest.source.getConnection();String sql = "select count(*) from customers";ScalarHandler scalarHandler = new ScalarHandler();Long count = (Long) queryRunner.query(conn, sql, scalarHandler);System.out.println(count);}
}

2 自定义 Handler

  • ResultSetHandler 是所有 Handler 实现的接口。
  • 自定义 Handler,重写 ResultSetHandler 接口下的 handle() 方法即可。
class MyHandler implements ResultSetHandler<Customer> {@Overridepublic Customer handle(ResultSet resultSet) throws SQLException {// 返回一条查询结果if (resultSet.next()) {int id = resultSet.getInt("id");String name = resultSet.getString("name");String email = resultSet.getString("email");Date birth = resultSet.getDate("birth");return new Customer(id, name, email, birth);} else {return null;}}}

3 资源的关闭

import org.apache.commons.dbutils.DbUtils;DbUtils.closeQuietly(connection);
DbUtils.closeQuietly(preparedStatement);
DbUtils.closeQuietly(resultSet);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307166.shtml

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

相关文章

.NET架构小技巧(3)——反射,架构人员法宝I

如题&#xff0c;这是我的心声&#xff0c;反射在我的开发中用的频次还是比较高的&#xff0c;有一本万利的感觉&#xff0c;一段复杂的代码&#xff0c;可以节省大量的时间&#xff1b;但带来的一个问题性能相对较差&#xff0c;所以要选择适合的场景使用。关于C#中的反射基本…

米家扫地机器人充满电需要多长时间_米家扫地机器人充满电后能工作多久?

硬件及结构相关1、Q&#xff1a;米家扫地机器人的激光对小孩或宠物有伤害吗&#xff1f;A&#xff1a;米家扫地机器人通过了IEC 60825-1:2014激光安全等级Class 1的认证&#xff0c;不会对儿童或者宠物带来伤害请放心使用。2硬件及结构相关1、Q&#xff1a;米家扫地机器人的激光…

后端学习 - JavaWeb

技术体系 文章目录一 HTML1 网页的组成部分2 HTML 概述3 HTML 标签4 常用标签5 表单与表单的提交二 CSS1 语法格式2 使用方法三 JavaScript1 概述2 与 HTML 结合的两种方式3 变量类型及特殊值4 关系、逻辑运算5 数组6 函数7 事件8 DOM &#xff08;Document Object Model&#…

python中的while语句怎么居中_python基础之while语句操作

# i 0# while (i < 9):# print("i ----> ",i)# i i 1# print(i,"i即将大于或者等于9,while不在执行")#执行1-100的数字# a1 1# while a1 < 100:# print(a1,end" ")# a1 a1 1#执行100 -1 的数字# a1 100# while a1 > 0:# prin…

心想技术驱动业务,却在背道而驰

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「165」篇原创敬上大家好&#xff0c;我是Z哥。相信每一位真正的程序员心里都有这样一个念想&#xff1a;只要我的技术够牛&#xff0c;就能驱动业务的发展。但是往…

后端学习 - SpringMVC

文章目录一 SpringMVC 简介1 MVC2 SpringMVC3 创建第一个 SpringMVC 项目二 RequestMapping1 注解类与方法的区别2 value 属性3 method 属性4 params 属性5 headers 属性6 SpringMVC 支持路径中的占位符三 获取 Request 的一系列参数1 通过控制器方法的形参2 控制器方法形参 映…

hbase shell远程连接_hbase与phoenix集成

Phoenix是构建在HBase之上的关系型数据库层&#xff0c;作为内嵌的客户端JDBC驱动用以对HBase中的数据进行低延迟访问Phoenix会将用户编写的sql查询编译为一系列的scan操作&#xff0c;最终产生通用的JDBC结果集返回给客户端Phoenix可以看成是mysql准备安装包apache-phoenix-4.…

对精致码农大佬的 [理解 volatile 关键字] 文章结论的思考和寻找真相

一&#xff1a;背景1. 讲故事昨天在园里的编辑头条看到 精致码农大佬 写的一篇题为&#xff1a;[C#.NET 拾遗补漏]10&#xff1a;理解 volatile 关键字 (https://www.cnblogs.com/willick/p/13889006.html) 的文章&#xff0c;大概就是说在 多线程环境下&#xff0c;一个在debu…

后端学习 - SpringBoot

SpringBoot 是整合 Spring 技术栈的一站式框架&#xff0c;是简化 Spring 技术栈的快速开发脚手架约定大于配置 文章目录一 概述1 第一个 SpringBoot 项目2 SpringBoot 特性&#xff1a;依赖管理3 SpringBoot 特性&#xff1a;自动配置二 SpringBoot 的 IOC容器1 组件添加&…

centos rpm 安装 perl_Linux【常用软件安装篇】

摘要&#xff1a;本文介绍Linux常用的软件安装方式以及jdk、vim、mysql、tomcat、redis的安装过程。1 Linux常用软件安装方式常用方式有&#xff1a;rmp包安装、yum指令安装、源码包安装、解压免安装。1.1 rpm包安装rpm是Red-Hat Package Manager&#xff08;RPM软件包管理器&a…

日计不足涓滴成河-自定义响应结果格式化器

什么是响应结果响应结果就是&#xff0c;在客户端向服务器发出请求后&#xff0c;服务器根据客户端的请求参数&#xff0c;给出的结果&#xff0c;这就是一个完整的响应结果过程。响应的结果包含的内容非常多&#xff0c;主要的有 HTTP Status Code&#xff0c;Content-Type,Co…

docker 容器启动顺序_Docker容器启动时初始化Mysql数据库

1. 前言 Docker在开发中使用的越来越多了&#xff0c;最近搞了一个Spring Boot应用&#xff0c;为了方便部署将Mysql也放在Docker中运行。那么怎么初始化 SQL脚本以及数据呢&#xff1f; 我这里有两个传统方案。 第一种方案是在容器启动后手动导入&#xff0c;太low了不行。第二…

后端学习 - JVM(上)内存与垃圾回收

JVM 架构图 文章目录一 JVM 简介二 类加载子系统&#xff1a;1 作用2 类的三个加载过程3 类加载器的分类4 双亲委派机制 & Tomcat为何不遵循5 两个 class 对象为同一个类的必要条件三 运行时数据区&#xff1a;PC寄存器&#xff08;Program Counter Register&#xff09;四…

SM2 国密算法被 Linux 内核社区接受

喜欢就关注我们吧&#xff01;10 月 25 日&#xff0c;有开发者发文称&#xff0c;SM2 国密算法终于被 Linux 内核社区接受了。该作者表示&#xff0c;SM2 的补丁已经更新到了 v7 版本&#xff0c;这个版本的补丁最终被社区接受&#xff0c;目前已经合并到了 Linux 主线的 5.10…

后端学习 - MyBatis

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的 持久层框架 文章目录一 基于配置文件的 MyBatis 搭建1 搭建过程&#xff08;增删改&#xff09;2 查询操作3 特殊操作二 MyBatis 获取参数值的方式1 单个字面量类型的参数2 多个字面量类型的参数3 Map 类型的参数4 实体…

向下兼容性格什么意思_担心对方只是向下兼容,并不是从心底里接纳我怎么办?...

无需刻意累计帮助了44人题主你好&#xff0c;不知道什么时候“向下兼容”这个词被用在了人际关系上&#xff0c;只就我个人所了解的话&#xff0c;这是一个很不严谨的用法。因为在自我接纳中用了“向下”本身就意味着不平等和不接纳。形容一个人“向下兼容”本身就自带了否认倾…

国产操作系统发展离不开人才和市场

日前&#xff0c;中国 1024 程序员节盛大举行&#xff0c;一大批开源大咖齐聚千年岳麓&#xff0c;围绕开源标准、生态、人才发展等主题分享&#xff0c;共议开源软件与操作系统未来。其中&#xff0c;统信软件总经理刘闻欢表示&#xff0c;“有了市场才会被真正的用起来”&…

zynq网络时钟控制寄存器_ZYNQ笔记(6):普通自定义IP封装实现PL精准定时中断...

软件的定时中断很难控制精准触发沿的位置&#xff0c;可以通过 PL-PS 的中断完成精准的定时中断。PL 的中断通过 Verilog 代码产生&#xff0c;这样紧密结合 PS-PL 的处理&#xff0c;发挥各自的优势。一、PL 侧定时中断1.实际要求① 上升沿中断&#xff1b;② 高电平宽度不小于…

后端学习 - Redis

文章目录一 Redis 概述Redis 为什么是单线程&#xff0c;单线程为什么这么快&#xff1f;数据存储结构二 常用数据类型1 String2 HashHash 的扩容机制&#xff1a;渐进式 rehash*3 List4 Set5 Zset三 Redis 事务1 乐观锁与 watch 命令2 事务的三个特性四 Redis 持久化1 RDB(Red…

再被补刀!Flash又遭抛弃,你会怀念它吗?

喜欢就关注我们吧&#xff01;微软近日发布通知&#xff0c;称更新了关于 Adobe Flash Player 的删除。微软更新目录站点可下载更新 KB4577586&#xff0c;用于删除 Flash Player。此更新适用于所有受支持的操作系统版本。重要版本 Windows 10 和 Windows 8.1 的可选更新也将在…