1.6 Java全栈开发前端+后端(全栈工程师进阶之路)-前置课程Jdbc编程,使用Java通过Jdbc对数据库进行基础操作

原理图

用java代码实现连接数据库(mysql)的操作

因为数据库连接需要使用到APIURL,下面简单介绍下API和URL的概念,

API:

Application Programming Interface应用程序编程接口,就是一套类库

Java中的API包括三个元素: API字节码、API源码、 API帮助文档

以上三个元素的版本要保持一致

例如:JDK1.8源码、JDK1.8字节码 和JDK1.8帮助文档,三者的版本要保持一致

URL

连接数据库时,需要使用URL连接,那么,什么是URL?

URl定义:

统一资源定位系统(uniform resource locator;URL)是因特网的万维网服务程序上用于指定信息位置的表示方法。它最初是由蒂姆·伯纳斯·李发明用来作为万维网的地址。现在它已经被万维网联盟编制为互联网标准RFC1738。(百度百科)

URL是统一资源定位符,代表网络中的某个资源的绝对路径

通过URL可以定位网络中的资源

URL主要包含四部分:协议、IP、端口号和资源名称

协议是: 提前制定好的通信数据格式、规范,按照这种特定格式发送数据包,对方收到数据包之后,也按照这种规范解析这个数据包,获取有价值数据

IP作用: 定位计算机

端口号作用: 定位服务

数据库中的URL:

如:MySQL

MySQL数据库:jdbc:mysql://localhost:3366/databaseName
a、jdbc:mysql://表示协议
b、localhost表示IP
c、3366表示端口号
d、databaseName表示数据库名称

SQL的分类

数据库查询语言(DQL)
简称:DQL,Data Query Language
代表关键字:select
DQL主要是查询表中的数据数据库操作语言(DML)
简称:DML,Data Manipulation Language
代表关键字:insert、delete 、update
DML主要是增、删、改表中的数据数据库定义语言(DDL)
简称:DDL,Data Denifition Language
代表关键字:create、drop、alter
DDL主要是创建、删除、修改表的结构事务控制语言(TCL)
简称:TCL,Trasactional Control Language
代表关键字:commit、rollback
TCL主要是对jdbc中的事务进行提交和回滚操作数据控制语言(DCL)
简称:DCL,Data Control Language
代表关键字:grant、revokeDML和DDL的区别是什么
DML是数据库操作语言,主要是修改数据库表中的数据,而DDL是数据库定义语言,主要修改数据中表的结构

JDBC编程六步曲

需要mysql驱动依赖:

        <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency>

第一步:注册驱动

  • 创建驱动对象,告知JDBC我们即将连接哪个数据库

  • 通过DriverManager.registerDriver(driver)注册驱动

  •         /*** <p>* 第一步:注册驱动* 通过创建驱动对象告知JDBC,我们即将连接哪个厂商的数据库* <p/>** @param* @return void* @Date 2020/6/7 11:23*/public static void registerDriver() {try {//注册驱动(new com.mysql.jdbc.Driver()也是可以的)Driver driver = new com.mysql.cj.jdbc.Driver();DriverManager.registerDriver(driver);} catch (SQLException e) {e.printStackTrace();}}
    

    第二步:获取数据库连接

  • 通过DriverManager.getConnection(url,user,pwd)获取连接

  • Connection连接对象不能随意创建,最后使用完要手动关闭

        /*** <p>* 第二步:获取数据库连接* 注意:Connection连接对象不能随意创建,最后使用完需要手动关闭* <p/>** @param* @return java.sql.Connection* @Date 2020/6/7 11:24*/public static Connection getConnection() {try {//注册驱动registerDriver();//获取数据库连接//url统一资源定位String url = "jdbc:mysql://ip:3306/test";String userName = "zhangsan";String passWord = "zhangsan@";Connection connection = DriverManager.getConnection(url, userName, passWord);//打印Connection对象的内存地址:com.mysql.cj.jdbc.ConnectionImpl@69d9c55System.out.println("MySql数据库,对java.sql.Connection接口的实现类的完整类名:" + connection);return connection;} catch (SQLException e) {e.printStackTrace();}return null;}

MySQL数据库默认支持的最多连接数量为100 我们大家都知道MySQL最大连接数的默认值是100,这个数值对于高并发下的应用是远远不够的,当连接请求大于默认连接数后,就会出现无法连接数据库的错误,因此我们需要把它适当调大一些。

在使用MySQL数据库的时候,经常会遇到这么一个问题,就是“Can not connect to MySQL server. Too many connections”-mysql 1040错误,这是因为访问MySQL且还未释放的连接数目已经达到MySQL的上限。通常,mysql的最大连接数默认是100,最大可以达到16384。

MySQL查看最大连接数和修改最大连接数:

查看最大连接数

show variables like '%max_connections%';

修改最大连接数

set GLOBAL max_connections = 2000;

也可以通过修改配置文件来修改mysql最大连接数(max_connections),这种方式说来很简单,只要修改MySQL配置文件my.ini或my.cnf的参数max_connections,将其改为max_connections=2000,然后重启MySQL即可。

第三步:获取数据库操作对象

  • 一个数据库连接对象可以创建多个数据库操作对象

  • 通过conn.createStatement()获取数据库操作对象

        /*** <p>* 第三步:获取数据库操作对象* 拿到Statement数据库操作对象,就可以执行sql语句* <p/>** @param* @return java.sql.Statement* @Date 2020/6/7 11:42*/public static Statement getStatement() {try {//获取数据库连接Connection connection = getConnection();//获取数据库操作对象//一个连接对象,可以获取多个数据库操作对象Statement statementOne = connection.createStatement();//打印Statement对象的内存地址:com.mysql.cj.jdbc.StatementImpl@23f7d05dSystem.out.println("MySql数据库,对java.sql.Statement接口的实现类的完整类名:" + statementOne);//打印Statement对象的内存地址:com.mysql.cj.jdbc.StatementImpl@1e730495//Statement statementTwo = connection.createStatement();//System.out.println("MySql数据库,对java.sql.Statement接口的实现类的完整类名:" + statementTwo);return statementOne;} catch (SQLException e) {e.printStackTrace();}return null;}

第四步:执行SQL语句

  • 通过数据库操作对象statement.executeUpdate(sql)编译执行SQL

  • JDBC编写SQL语句不需要以分号结尾

  • 数据库管理系统会将编写好的SQL语句编译并执行

        /*** <p>* 第四步:执行SQL语句* <p/>** @param* @return void* @Date 2020/6/7 11:51*/public static void executeSql() {try {//获取数据库操作对象Statement statement = getStatement();//执行SQL语句//注意:jdbc中,sql语句不需要以分好;结尾,当然,你写了也不会报错//定义DDL语句,这里可以创建表,但是,一般不这么玩,jdbc中,通常是写DML语句和DQL语句/*String sql = "CREATE TABLE `user` (\n" +"  `id` bigint(32) NOT NULL auto_increment,\n" +"  `userName` varchar(20) DEFAULT NULL COMMENT '用户名称',\n" +"  `email` varchar(128) DEFAULT NULL COMMENT '邮箱|登录帐号',\n" +"  `passWord` varchar(64) DEFAULT NULL COMMENT '密码',\n" +"  `createTime` datetime DEFAULT NULL COMMENT '创建时间',\n" +"  `lastLoginTime` datetime DEFAULT NULL COMMENT '最后登录时间',\n" +"  `status` bigint(1) DEFAULT '1' COMMENT '1:有效,0:禁止登录',\n" +"  PRIMARY KEY (`id`)\n" +") ENGINE=InnoDB DEFAULT CHARSET=utf8";*///定义DML语句String sql = StringUtils.join("insert into `user`(`userName`,`passWord`,`status`) values(", "'lisi','123','1')");//将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句int count = statement.executeUpdate(sql);System.out.println(count);} catch (SQLException e) {e.printStackTrace();}}

第五步:处理查询结果集

处理查询结果集,获取当前光标指向行中的数据,有三种方式:

第一种方式:根据字段下标获取,不管数据库表中的字段是什么类型,都以字符串方式取出,JDBC所有下标都是以1开始

第二种方式:通过结果集中字段名称获取数据,该方式的程序更加健壮,建议使用

第三种方式:通过特定类型获取数据,该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用

/*** <p>* 第五步:处理查询结果集* <p/>** @param* @return void* @Date 2020/6/7 12:48*/public static void dealResultSet() {try {//获取数据库操作对象Statement statement = getStatement();//定义DQL语句String sql = StringUtils.join("select * from `user` where userName = 'lisi'");//将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句,把查询结果集放到ResultSet结果集对象中ResultSet resultSet = statement.executeQuery(sql);//处理查询结果集,一个Statement可以得出多个ResultSet//resultSet.next()方法作用:if the new current row is valid, return true. if there are no more rows, return false//将光标向前移动一行,如果指向当前行有记录,则返回true,若指向当前行无记录,返回falsewhile (resultSet.next()) {//获取当前光标指向行中的数据,有三种方式://第一种方式:根据字段下标获取,不管数据库表中的字段是什么类型,都以字符串方式取出//JDBC所有下标都是以1开始String id1 = resultSet.getString(1);String userName1 = resultSet.getString(2);String status1 = resultSet.getString(7);System.out.println("id1:" + id1 + ",用户名1:" + userName1 + ",有效状态1:" + status1);//第二种方式:通过结果集中字段名称获取数据,该方式的程序更加健壮,建议使用String id2 = resultSet.getString("id");String userName2 = resultSet.getString("userName");String status2 = resultSet.getString("status");System.out.println("id2:" + id2 + ",用户名2:" + userName2 + ",有效状态2:" + status2);//第三种方式:通过特定类型获取数据,该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用int id3 = resultSet.getInt("id");String userName3 = resultSet.getString("userName");String status3 = resultSet.getString("status");System.out.println("id3:" + id3 + ",用户名3:" + userName3 + ",有效状态3:" + status3);}} catch (SQLException e) {e.printStackTrace();}}

第六步:释放资源

一个Connection可以创建多个Statement,一个Statement可以得出多个ResultSet,所以先关闭ResultSet,再关闭Statement,最后关闭Connection

需要关闭ResultSet、Statement、Connection

为了保障能够释放资源,将释放代码编写到finally语句中

分别进行try catch关闭资源

DBC驱动对象的创建、连接、获取数据库操作对象,执行sql、处理结果集等,都需要消耗时间,其中,这里面涉及到的ResultSet、Statement、Connection对象,使用完了需要释放,否则,造成资源浪费,严重的,服务器宕机

在编程时,由于用MySQL语句调用数据库时,在每次执行语句前,会做一个临时的变量用来打开数据库,所以你在使用MySQL语句的时候,记得在每次调用完MySQL之后就关闭MySQL临时变量。

         //释放资源部分代码片段catch (SQLException e){e.printStackTrace();} finally{//第六步:释放资源,分别进行try catch//从小的开始关闭try {if (resultSet != null) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}try {if (statement != null) {statement.close();}} catch (SQLException e) {e.printStackTrace();}try {if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}

JDBC编程六步曲小结

        /*** <p>* JDBC编程六部曲* 第一步:注册驱动* 第二步:获取数据库连接* 第三步:获取数据库操作对象* 第四步:执行SQL语句* 第五步:处理查询结果集* 第六步:释放资源* <p/>** @param* @return void* @Date 2020/6/7 13:32*/public static void jdbcProgram() {//定义数据库连接对象Connection connection = null;//定义数据库操作对象Statement statement = null;//定义处理结果集对象ResultSet resultSet = null;try {//第一步:注册驱动,通过创建驱动对象告知JDBC,我们即将连接哪个厂商的数据库//注册驱动(new com.mysql.jdbc.Driver()也是可以的)Driver driver = new com.mysql.cj.jdbc.Driver();DriverManager.registerDriver(driver);//第二步:获取数据库连接//注意:Connection连接对象不能随意创建,最后使用完需要手动关闭//url统一资源定位String url = "jdbc:mysql://ip:3306/test";String userName = "zhangsan";String passWord = "zhangsan@";connection = DriverManager.getConnection(url, userName, passWord);//第三步:获取数据库操作对象//一个连接对象,可以创建多个数据库操作对象statement = connection.createStatement();//第四步:执行SQL语句//注意:jdbc中,sql语句不需要以分好`;`结尾,当然,你写了也不会报错//定义DQL语句,jdbc中,通常是写DML语句和DQL语句String sql = StringUtils.join("select * from `user` where userName = 'lisi'");//将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句,把查询结果集放到ResultSet结果集对象中resultSet = statement.executeQuery(sql);//第五步:处理查询结果集//处理查询结果集,一个Statement可以得出多个ResultSet//resultSet.next()方法作用:if the new current row is valid, return true. if there are no more rows, return false//将光标向前移动一行,如果指向当前行有记录,则返回true,若指向当前行无记录,返回falsewhile (resultSet.next()) {//获取当前光标指向行中的数据(通过特定类型获取数据)//该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用int id = resultSet.getInt("id");String name = resultSet.getString("userName");String status = resultSet.getString("status");System.out.println("id:" + id + ",用户名:" + name + ",有效状态:" + status);}} catch (SQLException e) {e.printStackTrace();} finally {//第六步:释放资源,分别进行try catch//从小的开始关闭try {if (resultSet != null) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}try {if (statement != null) {statement.close();}} catch (SQLException e) {e.printStackTrace();}try {if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}}

JDBC编程六步曲优化

连接数据库的信息可在配置文件中进行配置,而不是硬编码到代码中

JDBC获取数据库连接有三种方式:

  • 通过键盘输入的方式(实际开发中也不会这样用)

  • 通过配置文件的方式(推荐使用)

  • 直接在数据库连接时,硬编码定义在程序中(不推荐)

通过键盘输入的方式(不推荐)

        /*** <p>* 通过键盘输入的方式,获取数据库连接(实际开发中也不会这样用)* <p/>** @param* @return java.sql.Connection* @Date 2020/6/7 14:14*/public static Connection getConnectionByStream() {try {System.out.println("----方式1-从控制台,通过键盘输入获取连接数据库的相关信息-----");//键盘输入/*InputStream inputStream = System.in;InputStreamReader inputStreamReader = new InputStreamReader(inputStream);BufferedReader reader = new BufferedReader(inputStreamReader);*///以上三行代码可以合为一行BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入数据库连接时注册驱动");String driver = reader.readLine();System.out.println("请输入数据库连接时的url");String url = reader.readLine();System.out.println("请输入数据库连接时的用户名user");String userName = reader.readLine();System.out.println("请输入数据库连接时的用户名密码");String passWord = reader.readLine();//关闭流reader.close();System.out.println("-----------------连接数据库--------------------");//注册驱动,这里必须是完整的类名(包名+类名)Class.forName(driver);//创建数据库连接Connection connection = DriverManager.getConnection(url, userName, passWord);return connection;} catch (IOException | ClassNotFoundException | SQLException e) {e.printStackTrace();}return null;}

通过配置文件的方式(推荐使用)

1、创建db.properties配置文件,内容如下

        #数据库连接配置db.driver=com.mysql.cj.jdbc.Driverdb.url=jdbc:mysql://ip:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=PRC&useSSL=falsedb.username=zhangsandb.password=zhangsan@

2、通过FileReader fileReader = new FileReader(“db.properties”);读取配置文件

3、创建属性对象Properties pro = new Properties();

4、通过属性对象pro.load(reader)方法将配置信息读取到Map集合对象中(内存中)

5、关闭流 reader.close();

6、通过属性对象的getProperty(String key)方法获取配置文件中的value属性值

7、通过获取到的连接信息,创建数据库连接

        /*** <p>* 通过配置文件的方式,获取数据库连接(推荐使用)* <p/>** @param* @return java.sql.Connection* @Date 2020/6/7 14:14*/public static Connection getConnectionByConfiguration() {try {System.out.println("-----------方式2-读取配置文件---------------");//1.读取配置文件InputStream inputStream = JDBCTest002.class.getClassLoader().getResourceAsStream("db.properties");//2.创建属性对象Properties pro = new Properties();//3.通过属性对象的load()方法将配置文件读取到流中(Map集合对象中(内存中))pro.load(inputStream);//4.关闭流inputStream.close();//5.通过属性对象的getProperty(String key)方法获取配置文件中的value属性值String driver = pro.getProperty("db.driver");String url = pro.getProperty("db.url");String userName = pro.getProperty("db.username");String passWord = pro.getProperty("db.password");System.out.println("-----------------连接数据库--------------------");//注册驱动,这里必须是完整的类名(包名+类名)Class.forName(driver);//创建数据库连接Connection connection = DriverManager.getConnection(url, userName, passWord);return connection;} catch (IOException | ClassNotFoundException | SQLException e) {e.printStackTrace();}return null;}

数据库连接时,硬编码在程序中(不推荐)

         //第二步:获取数据库连接//注意:Connection连接对象不能随意创建,最后使用完需要手动关闭//url统一资源定位String url = "jdbc:mysql://ip:3306/test";String userName = "zhangsan";String passWord = "zhangsan@";connection = DriverManager.getConnection(url, userName, passWord);

Statement 和 PreparedStatement

JDBC中,Statement 和 PreparedStatement这两个都是数据库操作对象,都可以操作sql获取到想要的结果,但是,这两个还是有一些差别。

SQL注入现象

SQL注入定义

定义

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

SQL是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL。而SQL注入是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。如Web应用程序的开发人员对用户所输入的数据或cookie等内容不进行过滤或验证(即存在注入点)就直接传输给数据库,就可能导致拼接的SQL被执行,获取对数据库的信息以及提权,发生SQL注入攻击。 (百度百科)

SQL注入实例

假设有一个场景: 用户通过进行用户名称,进行精确查询,用户输入的信息中有SQL关键字,并且参与了SQL语句的编译,导致SQL语句含义扭曲,最终导致了SQL注入。用户本来只应该查询到他自己的信息,但是却查出来了所有的用户信息。

SQL注入,简单来说,就是用一些SQL关键字,来导致一些不正常的现象,下面的这条sql,由于and优先级高于or,在用户录入userName = 'lisi' or 'hello' = 'hello'信息进行查询时,执行时sql就变成了select * from user where status = 1 and userName = 'lisi' or 'hello' = 'hello',导致SQL语句条件永远为真,会查出所有的用户信息数据。

select * from `user` where status = 1 and userName = {userName }

以上SQL注入原因分析: 由于and优先级高于or,该条sql最终执行时,查询条件被分为两部分(status = 1 and userName = 'lisi') or 'hello' = 'hello',导致SQL语句条件永远为真,会查出所有的用户信息数据。

如何解决SQL注入呢

定义SQL语句框架的时候,使用PreparedStatement数据库操作对象,这个是预编译对象,先将SQL语句框架进行了编译,然后给参数?动态赋值

先定义 SQL 语句构架,然后对SQL语句进行预先编译,select * from user where status = ? and userName = ? ps = conn.prepareStatement(sql);

然后再接收用户提供的信息,即使用户提供的信息中包含SQL关键字,这些关键字也不参 与编译,是不起作用的。

主要修改的部分:

通过日志也可以看出,即使用户提供的信息中包含SQL关键字,这些关键字也不参

与编译,是不起作用的

预编译SQL:select * from user where status = ? and userName = ?

赋值后,编译的SQL: select * from user where status = ‘1’ and userName = ‘\'lisi\' or \'hello\' = \'hello\'’,其实编译后的sql,是把用户录入的'lisi' or 'hello' = 'hello',整体作为了一个字符串,即执行的sql是:select * from user where status = ‘1’ and userName = “'lisi\' or \'hello\' = \'hello\'”,这样就不会发生SQL注入问题了。

Statement 和 PreparedStatement 对比

PreparedStatement可以防止 SQL 注入,执行效率高

SQL语句对于Statement来说是:编译一次执行一次

SQL语句对于PreparedStatement来说,是编译一次执行N次

原因:数据库管理系统(DBMS)厂商实现了JDBC接口,DBMS将编译后的SQL语句保存在DBMS中,由于DBMS中有很多编译好的SQL语句,这时通过同一个PreparedStatement对象进行赋值,便会找到其对应的PreparedStatement对象,从而实现其参数的赋值,即:一次编译多次执行。

PreparedStatement是类型安全的,编译期可以检查传入参数类型

JDBC事务

事务的定义

事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

事务是恢复和并发控制的基本单位

事务的四个特性

事务应该具有4个属性:原子性、一致性、隔离性、持久性,这四个属性通常称为ACID特性。

原子性(atomicity)

一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。

一致性(consistency)

事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)

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

持久性(durability)

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

JDBC中的事务

操作数据库时,肯定会有事务的存在,那么,JDBC中的事务是怎么使用的呢?

  • JDBC默认情况下,事务是自动提交的:即在JDBC中执行一条DML语句就执行了一次事务

  • 将事务的自动提交,修改为手动提交即可避免自动提交

  • 在事务执行的过程中,任何一步出现异常都要进行回滚

JDBC中使用事务只有三行代码:

  • 设置手动提交事务:conn.setAutoCommit(false);

  • 事务提交:conn.commit();

  • 事务回滚:conn.rollback();

在获取数据库连接后面开启事务,在 catch 语句块中进行事务回滚

JDBC编程六步曲最终版

经过以上详细的介绍,相信童鞋们也对JDBC编程有了详细的认识,下面,给出最终版的JDBC编程六部曲代码,以后使用的时候,可以直接copy,进行简单修改即可。

        /*** <p>* JDBC编程六部曲* 第一步:注册驱动* 第二步:获取数据库连接* 第三步:获取数据库操作对象* 第四步:执行SQL语句* 第五步:处理查询结果集* 第六步:释放资源* <p/>** @param* @return void* @Date 2020/6/7 15:50*/public static void jdbcProgramFinal() {//定义数据库连接对象Connection connection = null;//定义数据库操作对象PreparedStatement preparedStatement = null;//定义处理结果集对象ResultSet resultSet = null;try {//第一步:注册驱动,通过创建驱动对象告知JDBC,我们即将连接哪个厂商的数据库//注册驱动(new com.mysql.jdbc.Driver()也是可以的)/* Driver driver = new com.mysql.cj.jdbc.Driver();DriverManager.registerDriver(driver);*///第二步:获取数据库连接(这里面已经注册过驱动了,如果使用这种方式,上面就不用注册驱动了)//注意:Connection连接对象不能随意创建,最后使用完需要手动关闭//通过配置文件的方式(推荐使用)connection = getConnectionByConfiguration();//第三步:获取数据库操作对象(一个连接对象,可以创建多个数据库操作对象)if (connection == null) {System.out.println("获取数据库连接失败!");return;}//定义DQL语句,jdbc中,通常是写DML语句和DQL语句//定义SQL语句框架String sql = StringUtils.join("select * from `user` where status = ? and userName = ?");//执行到此,先将SQL语句框架进行了编译preparedStatement = connection.prepareStatement(sql);//这里假设是前台传的参数值String statusParam = "1";String userNameParam = "'lisi' or 'hello' = 'hello'";//给参数?动态赋值preparedStatement.setString(1, statusParam);preparedStatement.setString(2, userNameParam);//打印预编译SQL//System.out.println("预编译SQL:" + ((ClientPreparedStatement) preparedStatement).getPreparedSql());//打印赋值后,编译的SQL//System.out.println("赋值后,编译的SQL:" + ((ClientPreparedStatement) preparedStatement).asSql());//第四步:执行SQL语句//将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句,把查询结果集放到ResultSet结果集对象中resultSet = preparedStatement.executeQuery();//第五步:处理查询结果集//处理查询结果集,一个Statement可以得出多个ResultSet//resultSet.next()方法作用:if the new current row is valid, return true. if there are no more rows, return false//将光标向前移动一行,如果指向当前行有记录,则返回true,若指向当前行无记录,返回falsewhile (resultSet.next()) {//获取当前光标指向行中的数据(通过特定类型获取数据),该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用int id = resultSet.getInt("id");String name = resultSet.getString("userName");String status = resultSet.getString("status");System.out.println("id:" + id + ",用户名:" + name + ",有效状态:" + status);}} catch (SQLException e) {e.printStackTrace();} finally {//第六步:释放资源,从小的开始关闭,分别进行try catchtry {if (resultSet != null) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}try {if (preparedStatement != null) {preparedStatement.close();}} catch (SQLException e) {e.printStackTrace();}try {if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}}/*** <p>* 通过配置文件的方式,获取数据库连接(推荐使用)* <p/>** @param* @return java.sql.Connection* @Date 2020/6/7 14:14*/public static Connection getConnectionByConfiguration() {try {//1.读取配置文件InputStream inputStream = JDBCTest003.class.getClassLoader().getResourceAsStream("db.properties");//2.创建属性对象Properties pro = new Properties();//3.通过属性对象的load()方法将配置文件读取到流中(Map集合对象中(内存中))pro.load(inputStream);//4.关闭流inputStream.close();//5.通过属性对象的getProperty(String key)方法获取配置文件中的value属性值String driver = pro.getProperty("db.driver");String url = pro.getProperty("db.url");String userName = pro.getProperty("db.username");String passWord = pro.getProperty("db.password");//注册驱动,这里必须是完整的类名(包名+类名)Class.forName(driver);//创建数据库连接Connection connection = DriverManager.getConnection(url, userName, passWord);return connection;} catch (IOException | ClassNotFoundException | SQLException e) {e.printStackTrace();}return null;}

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

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

相关文章

KaiwuDB 解析器之语义解析

KaiwuDB 解析器介绍 解析器是数据库系统的重要组成部分之一&#xff0c;主要的功能是将客户端输入的 SQL 语句分解为语法单元&#xff0c;然后将这些语法单元转化成数据库内部可识别的数据结构&#xff0c;最终生成数据库可以执行的计划。 KaiwuDB 的一条 SQL 执行的整个生命…

SQL 基础 | AVG 函数的用法

在SQL中&#xff0c;AVG()是一个聚合函数&#xff0c;用来计算某个列中所有值的平均值。 它通常与GROUP BY子句一起使用&#xff0c;以便对分组后的数据进行平均值计算。 AVG()函数在需要了解数据集中某个数值列的中心趋势时非常有用。 以下是AVG()函数的一些常见用法&#xff…

Java集合排序

1. 集合排序API 1.1 集合排序概述 集合排序是指对一个集合中的元素按照特定规则进行重新排列&#xff0c;以使得集合中的元素按照预定义的顺序呈现。 在集合排序中&#xff0c;通常需要定义一个比较规则&#xff0c;这个比较规则用于决定集合中的元素在排序后的顺序。元素之间…

本地部署开源白板工具Excalidraw并结合内网穿透远程绘制流程图

文章目录 1. 安装Docker2. 使用Docker拉取Excalidraw镜像3. 创建并启动Excalidraw容器4. 本地连接测试5. 公网远程访问本地Excalidraw5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 本文主要介绍如何在Ubuntu系统使用Docker部署开源白板工具Excal…

渗透测试工具--awvs

安装 pull 这个镜像&#xff0c;注&#xff1a;内部映射端口 3443 软件页面 UserName: awvsawvs.lan PassWord: Awvsawvs.lan 或 使用以下命令无脑安装 bash <(curl -sLk https://www.fahai.org/aDisk/Awvs/check.sh) xrsec/awvs:preview 样式如下 若未成功&#xff0…

【网络原理】HTTPS 的工作过程

系列文章目录 【网络通信基础】网络中的常见基本概念 【网络编程】网络编程中的基本概念及Java实现UDP、TCP客户端服务器程序&#xff08;万字博文&#xff09; 【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制&#xff08;CRC算法、MD5算法&#xff09; 【网络…

面试集中营—Redis架构篇

一、Redis到底是多线程还是单线程 1、redis6.0版本之前的单线程&#xff0c;是指网络请求I/O与数据的读写是由一个线程完成的&#xff1b; 2、redis6.0版本升级成了多线程&#xff0c;指的是在网络请求I/O阶段应用的多线程技术&#xff1b;而键值对的读写还是由单线程完成的。所…

【prometheus】Pushgateway安装和使用

目录 一、Pushgateway概述 1.1 Pushgateway简介 1.2 Pushgateway优点 1.3 pushgateway缺点 二、测试环境 三、安装测试 3.1 pushgateway安装 3.2 prometheus添加pushgateway 3.3 推送指定的数据格式到pushgateway 1.添加单条数据 2.添加复杂数据 3.SDk-prometheus-…

C语言 举例说明循环嵌套

今天 我们来说循环的嵌套 如果一个循环体内 又包含了另一个循环结构 我们称之为循环的嵌套 我们之前学的 While do-while for 都可以进行相互的嵌套 如下图 在 While 循环语句中再嵌套一个 While 循环语句 do-while 中嵌套 do-while for中嵌套 for 例如 我们做一个九九乘法…

Oracle Database 23ai 正式发布,超级巨兽(集关系型、向量、文档、图、缓存、分布式数据库一体的全能数据库)

Oracle23c改名为Oracle23ai&#xff0c;也意味着Oracle数据库正式从Cloud进入AI时代。Oracle23ai版本是一个超级巨兽&#xff0c;简单总结下&#xff1a; AI能力&#xff1a;内置向量数据库&#xff0c;内置ONNX模型数据处理&#xff0c;内置Text2SQL&#xff0c;内置的机器学习…

QT5之lambda+内存回收机制

使用lambda需要 配置c11 所以在点.pro文件里面配置添加如下 CONFIG c11 使用到qDebug 打印包含头文件 #include<QDebug> lambda 表达式使用 代替槽如下 #include "mainwidget.h" #include<QPushButton> #include<QDebug> mainWidget::mainWid…

js模块化:修改导入模块的内容,会有影响吗?

起因 element-ui的popper组件相关的层级&#xff0c;是使用popup-manager来统一管理的。 之前试图在自己的组件里导入并使用element-ui的popup-manager&#xff0c;但是层级老是和element-ui组件的层级冲突&#xff0c;看了下源码&#xff0c;竟意外发现&#xff0c;使用popu…

毕业设计参考-PyQt5-YOLOv8-鱼头鱼尾鱼长测量程序,OpenCV、Modbus通信、YOLO目标检测综合应用

“PyQt5-YOLOv8-鱼头鱼尾鱼长测量程序”是一个特定的软件程序&#xff0c;用于通过图像处理和目标检测技术来测量鱼类的长度。 视频效果&#xff1a; 【毕业设计】基于yolo算法与传统机器视觉的鱼头鱼尾识别_哔哩哔哩_bilibili 这个程序结合了多种技术&#xff1a; 1. OpenCV…

【Linux极简教程】常见实用命令不断更新中......

【Linux极简教程】常见实用命令不断更新中...... 常见问题1.Waiting for cache lock: Could not get lock /var/lib/dpkg/lock. It is held by process xxxx(dpkg) 常见问题 1.Waiting for cache lock: Could not get lock /var/lib/dpkg/lock. It is held by process xxxx(dp…

【Docker】★★★

docker 的网络模式 ●host模式&#xff1a;使用 --nethost 指定 容器与宿主机共享网络命名空间、ip和端口 ●container模式&#xff1a;使用 --netcontainer:NAME_or_ID 指定 新建的容器共享已有容器的网络命名空间、ip和端口 ●none模式&#xff1a;使用 --netnone 指定 不进行…

阿里实习生:面试阿里其实并没有那么难。

愉快的五一假期已经结束了, 又要投入到学习和工作当中了。 今天分享一位同学在阿里的Go后端实习面经详解, 希望对你有帮助。 Go里有哪些数据结构是并发安全的&#xff1f; 并发安全就是程序在并发的情况下执行的结果都是正确的&#xff1b; Go中数据类型分为两大类&#xff…

24年最新抖音、视频号0成本挂机,单号每天收益上百,可无限挂

详情介绍 这次给大家带来5月份最新的短视频挂机项目&#xff0c;简单易上手&#xff0c;而且不需要任何投入&#xff0c;经过测试收益非常可观&#xff0c;软件完全免费&#xff0c;特别适合没有时间但是想做副业的家人们

ai生图什么软件好?推荐7个不错的AI绘画软件

ai生图什么软件好&#xff1f;推荐7个不错的AI绘画软件&#xff01;小编带你进入一个创意与科技交融的奇妙世界——AI绘画&#xff0c;让我们一同领略其中的魅力吧~ 一、爱制作AI 这款AI人工智能软件是一款多功能的工具平台&#xff0c;集合了AI问答、AI绘画和AI智能写作等功能…

在离线环境中将运行 Oracle DB 12c 的 CentOS 7.5 原地升级并迁移至 RHEL 7.9

《OpenShift / RHEL / DevSecOps 汇总目录》 说明 本文只是说明如何在 CentOS 7.5 上准备 Oracle DB 12c 验证环境&#xff0c;而将该环境升级并迁移至 RHEL 7.9 的操作过程请参见&#xff1a;《在离线环境中将 CentOS 7.5 原地升级并迁移至 RHEL 7.9》一文。 另外&#xff…

我希望未来10年,人工智能可以帮我解决这4件小事

生活在一线大城市的我&#xff0c;现在几乎整天被大数据、人工智能、机器学习、智慧生活的词汇环绕立体包围着&#xff0c;让我时刻感觉到&#xff0c;再过10年&#xff0c;我们五一假期真的可以摆脱现在擦肩接踵的旅游盛况了。但我其实要求倒是没这么高&#xff0c;我真心希望…