失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 数据库连接之jdbc连接池

数据库连接之jdbc连接池

时间:2020-11-15 02:14:32

相关推荐

数据库连接之jdbc连接池

BC

1. 概念:Java DataBase Connectivity Java 数据库连接, Java语言操作数据库

JDBC本质:官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口,shi连接数据库的桥梁。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

jdbcAPI:与数据库建立连接、执行SQL 语句、处理结果

DriverManager :依据数据库的不同,管理JDBC驱动

Connection :负责【连接数据库并担任传送】数据的任务

Statement :由 Connection 产生、【负责执行SQL】语句

ResultSet:负责【保存Statement执行后所产生的查询结果】

1-1使用纯Java方式连接数据库

由JDBC驱动直接访问数据库

优点:完全Java代码,快速、跨平台

缺点:访问不同的数据库需要下载专用的JDBC驱动

1-2使用JDBC-ODBC桥方式连接数据库

将对JDBC API的调用,转换为对另一组数据库连接API的调用

优点:可以访问所有ODBC可以访问的数据库

缺点:执行效率低、功能不够强大

jdbc:mysql:///kgc?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=utf-8

MySQL 8.0 以上修改时区域 两种方式以及中文编码

【驱动必须加cj】

推荐:Class.forName(“com.mysql.cj.jdbc.Driver”);

不推荐DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());

【安全套接字协议ssl】

url 中添加useSSL=true

Jdbc程序中的DriverManager用于加载驱动,并创建与数据库的链接,这个API的常用方法:DriverManager.registerDriver(new Driver()) DriverManager.getConnection(url, user, password)注意:在实际开发中并不推荐采用registerDriver方法注册驱动。原因有二:1. 查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象【一次是加载驱动,一次是获得连接】。2. 程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。推荐方式:Class.forName("com.mysql.cj.jdbc.Driver");采用此种方式不会导致驱动对象在【内存中重复出现】,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖【具体的驱动】,使程序的【灵活性更高】

1. 在客户端中修改时区

set global time_zone = ‘+8:00’;

set time_zone = ‘+8:00’;

show variables like ‘%time_zone%’;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DofrZuXg-1604303154959)(JDBC/image-192142434.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UYa55F1A-1604303154961)(C:UsersASUSAppDataRoamingTyporatypora-user-imagesimage-24124.png)]

2.每次连接数据库时的url中在库名后添加

?serverTimezone=UTC

防止中文乱码:

?useUnicode=true&characterEncoding=utf-8

con=DriverManager.getConnection(“jdbc:mysql://localhost:3306/kgc?serverTimezone=UTC”, “root”, “123456”);

2.详解各个对象:

2-1. DriverManager:驱动管理对象

功能:驱动管理使用前需要先进行导包注意:

mysql5之后的驱动jar包可以省略注册驱动的步骤。

导入驱动jar包 mysql-connector-java-5.1.37-bin.jar或者mysql-connector-java-8.0.20.jar【1.复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下2.右键–>【idea用Add As Library】【ecliise用buildpath放入到【在src包下建一个lib包】中】

1-1 注册驱动:告诉程序该使用哪一个数据库驱动jar

可以添加不同数据库的驱动【需要下载对应的架包】

static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。

//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());不推荐使用

这种方式来加载驱动

写代码使用: Class.forName(“com.mysql.jdbc.Driver”);

通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块

static {

try {

​ java.sql.DriverManager.registerDriver(new Driver());

} catch (SQLException E) {

​ throw new RuntimeException(“Can’t register driver!”);

}

}

2-1-1.0 常见数据库写法以及Url祥解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kp5FYlxe-1604303154963)(JDBC/image-075412981.png)]

注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。

2-2. 获取数据库连接con:

方法1:【三个参数分开写】

static Connection getConnection(String url, String user, String password)

方法2:【三个参数写在一起】

static Connection getConnection("jdbc:/mysql:///kgc&useSSL=true? user=root&password=123456”)

参数:

url:指定连接的路径

语法:jdbc:mysql://ip地址(域名):端口号/数据库名称

例子:jdbc:mysql://localhost:3306/db3

细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称

user:用户名

password:密码

Connection:数据库连接对象

功能:

获取执行sql 的对象

2. 管理事务:

开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务

提交事务:commit()

回滚事务:rollback()

2-3Statement:执行sql的对象[【编译与预编译】

Jdbc程序中的Statement对象用于【向数据库发送SQL语句】,Statement对象常用方法: 【如果是preparedstatement不加参数sql】executeQuery(String sql) :用于向数据发送查询语句。 executeUpdate(String sql):用于向数据库发送insert、update或delete语句 execute(String sql):用于向数据库发送任意sql语句 addBatch(String sql) :把多条sql语句放到一个批处理中。 executeBatch():向数据库发送一批sql语句执行。

Statement createStatement()

PreparedStatement prepareStatement(String sql)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G11kZbSG-1604303154964)(JDBC/image-113028668.png)]

2-4执行SQL语句返回结果集或者行数;

执行sql

2-3-1boolean execute(String sql) :可以执行任意的sql 了解

-3-2int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句

返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。

2-3-3 ResultSet executeQuery(String sql) :执行DQL(select)语句

account表 添加一条记录​int count = stmt.executeUpdate(sql);//影响的行数​System.out.println(count);​if(count > 0){​ System.out.println("添加成功!");​}else{​ System.out.println("添加失败!");​}

2-4-1ResultSet:结果集对象,封装查询结果

boolean next(): 【游标】向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true

默认游标指向第一行结果之前

getXxx(参数):获取数据

Xxx:代表数据类型 如: int getInt() , String getString()

while(it.next()){

//根据获取【列】的数据类型或者是字段下标,分别调用rs的相应方法【映射到java对象】中

syso(rs.getInt(1)+“\t学员名字”+rs.getString(student_name));

}

可以用getString()接收任何数据类型

【增删改时,在预编译后,通过预编译对象可以用setString()给任何下标进行赋值】

参数:

int:代表列的编号,从1开始 如: getString(1)

String:代表列名称。 如: getDouble(“balance”)

使用步骤:

游标向下移动一行

判断是否有数据

获取数据

//循环判断游标是否是最后一行末尾。

ResultSet【用来接收stm预编译对象执行SQL语句的结果】既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法: 获取任意类型的数据 getObject(int index) getObject(string columnName) 获取指定类型的数据,例如: getString(int index) //根据下标获取对象的值getString(String columnName) //根据字段名(列)获取对象的值ResultSet还提供了对结果集进行滚动的方法: next():移动到下一行 Previous():移动到前一行 absolute(int row):移动到指定行 beforeFirst():移动resultSet的最前面。 afterLast() :移动到resultSet的最后面

2-4-2结果集获得当前日期【插入或更改时的日期】进行日期赋值

preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));//给第五个占位符? 的值赋值为new Date(new java.util.Date().getTime());//插入当前时间

也可以手动输入stm.setString(“ -10-20 12-00-00”);

select UTC_TIMESTAMP() 获取世界标准是时间select EXTRACT(HOUR FROM TIMEDIFF(NOW() ,UTC_TIMESTAMP())) 数据库时间与标准时间 相差的时间DATE_FORMAT()函数将时间戳转换为日期格式:比如降1455504268→-02-15 10:44:281 select device.register_time a,FROM_UNIXTIME(device.register_time,'%Y-%m-%d %H:%i:%s') as registerTime from tm_data_newdevice device

2-4-5可 将时间戳转换为日期格式:比如降1455504268→-02-15 10:44:28

1 select device.register_time a,FROM_UNIXTIME(device.register_time,'%Y-%m-%d %H:%i:%s') as registerTime from tm_data_newdevice device

列号或列名标识列

while ( rs.next() ) {System.out.print( rs.getInt(1) +"t");System.out.print( rs.getString(2) +"t");System.out.print(rs.getInt("loginPassword")+ "t");… …}

while(rs.next()){​ //获取数据​ System.out.println(rs.getInt(1) + "---" + rs.getString("name") + "---" + rs.getDouble(3)+rs.getDate(4));​}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dXJENiEs-1604303154965)(C:UsersASUSAppDataRoamingTyporatypora-user-imagesimage-201837104.png)]

2-4-6查询【聚合函数】

例如查询count(1)查询学生人数结果是单列,

1.可以直接在

while(rs.next()){

system.out.println(rs.getInt(1));//第一列的值StringInt

//2system.out.println(rs.getInt(“总人数”));//要么聚合函数必须起别名。

package cn.kgc.tangcco.test1021;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Scanner;public class TestJuheFunction {public static void main(String[] args) throws SQLException {//声明接口和手动输入关键字;Connection con=null;ResultSet rs=null;PreparedStatement stm=null;Scanner input = new Scanner(System.in);try {Class.forName("com.mysql.cj.jdbc.Driver");//2.获得连接con=DriverManager.getConnection("jdbc:mysql:///kgc", "root", "123456");//3.编写sql语句并预编译,执行String sql="select count(1) 总人数 from student";//String sql="select count(1) studentNums from student";//起中英文别名都行stm=con.prepareStatement(sql);//4.接收预编译对象的数据并遍历rs=stm.executeQuery();while (rs.next()) {System.out.println(rs.getInt("总人数"));// System.out.println(rs.getInt(studentNums)); //此时用英文做变量名 }} catch (Exception e) {e.printStackTrace();}finally {if (rs!=null) {rs.close();}if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}/48/

}

2-5释放资源

释放ResultSet, Statement,Connection。

数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致【系统宕机】Connection的使用原则是尽量晚创建,尽量早的释放

。关闭资源

可以关闭结果集、命令、连接

注意:注意顺序,倒着关闭

连接若从连接池(后面讲)获取,不需要关闭

3.SQL注入问题与占位符?

所谓SQL注入,

就是通过把SQL命令插入到Web表单提交或页面请求url的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

【利用or或者是– 注释符号及引号。获取所有人的密码或者免验证登录;利用statement需要拼接sql语句的漏洞】在预编译的过程中添加的内容只会作为字符段的一部分,不会改变sql语句的结构;

不要以为在输入框做个检查就够了,不要忘记了,我们web提交表单,是可以模拟url直接访问过去,绕开前段检查。因此,必须是后端,或是数据来检查才能有效防止。

(1)检查用户输入的合法性;【输入框验证】

(2)将用户的登录名、密码等数据加密保存。【md5加盐】

(3)预处理SQL。【采用占位符,无论输入什么,都作为字段内容】

(4)使用存储过程实现查询,虽然不推荐,但也是一个方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9pqvimka-1604303154966)(C:UsersASUSAppDataRoamingTyporatypora-user-imagesimage-203808157.png)]

MySQL预处理是怎么防止的呢?

其实是因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1’也数据库会作为【一个参数一个字段的属性值】来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了

:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题

输入用户随便,输入密码:a’ or ‘a’ = 'a

sql:select from user where username = ‘fhdsjkf’ and password = ‘a’ or ‘a’ = ‘a’

解决sql注入问题:使用PreparedStatement对象来解决

预编译的SQL:参数使用?作为占位符

步骤:

导入驱动jar包 mysql-connector-java-5.1.37-bin.jar

注册驱动

获取数据库连接对象 Connection

定义sql

注意:sql的参数使用?作为占位符。 如:select from user where username = ? and password = ?;

获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)

6. 给?赋值:

方法: setXxx(参数1,参数2)

参数1:?的位置编号 从1 开始

参数2:?的值

执行sql,接受返回结果,不需要传递sql语句

处理结果

释放资源

注意:后期都会使用PreparedStatement来完成增删改查的所有操作

可以防止SQL注入

效率更高

4.编译[【需要while(rs.next())获得结果集】

ResultSet executeQuery(String sql) 执行SQL查询并获取到ResultSet对象

int executeUpdate(String sql) 可以执行插入、删除、更新等操作,返回值是执行该操作所影响的行数

boolean execute(String sql) 可以执行任意SQL语句,然后获得一个布尔值,表示是否返回ResultSet

更新:/,修改删除

package cn.kgc.tyl.test1020;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class UpdateStatement {public static void main(String[] args) throws SQLException {Connection con=null;Statement stm=null;try {//1.加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//2.获得连接con=DriverManager.getConnection("jdbc:mysql://localhost:3306/kgc?serverTimezone=UTC", "root", "123456");if (con!=null) {System.out.println("连接成功");}// 3.写sql语句并编译【先写SQL语句再执行可能出现SQL注入的问题,不安全;】编译必须用编译对象接收,否则空指针异常String sql3="update student set student_name= '远哥' where student_num=3";// stm = con.createStatement(); int count=stm.executeUpdate(sql3);//返回为int类型if (count>0) {System.out.println("修改成功");}else {System.out.println("修改失败");}} catch (Exception e) {e.printStackTrace();}finally {if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}/更新成功/

查询

package cn.kgc.tyl.test1020;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class SelectStatement {public static void main(String[] args) throws SQLException {Connection con=null;Statement stm=null;ResultSet rs=null;try {//1.加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//2.获得连接con=DriverManager.getConnection("jdbc:mysql://localhost:3306/kgc?serverTimezone=UTC", "root", "123456");if (con!=null) {System.out.println("连接成功");}// 3.写sql语句并编译【先写SQL语句再执行可能出现SQL注入的问题,不安全;】String sql1="select * from student";stm= con.createStatement();// 4.用结果集接收执行的sql语句并输出rs=stm.executeQuery(sql1);while (rs.next()) {System.out.println(rs.getInt("student_num")+"姓名"+rs.getString("student_name"));//com.mysql.cj.jdbc.result.ResultSetImpl@6366ebe0}} catch (Exception e) {e.printStackTrace();}finally {if (rs!=null) {rs.close();}if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}/连接成功1姓名远哥2姓名远哥3姓名Lucy4姓名韩文5姓名果果6姓名狂龙7姓名赵18姓名赵29姓名赵310姓名赵411姓名赵512姓名赵614姓名赵1415姓名赵1520000姓名赵1617姓名赵1718姓名赵1819姓名赵1920姓名赵姓名赵2122姓名赵2224姓名赵2425姓名赵李72姓名赵李李173姓名赵李174姓名李赵175姓名李163姓名赵2526姓名赵2627姓名赵2728姓名赵2829姓名赵2930姓名赵3031姓名赵3132姓名赵3233姓名赵3334姓名赵3435姓名赵3536姓名赵3637姓名赵3738姓名赵3839姓名赵3948姓名赵4010000姓名张三11000姓名张非/

5.预编译【获得预编译对象后,要对占位符的对象赋值】

5-1预编译的好处:

【提高了安全性;提高了SQL语句执行的性能;提高了代码的可读性和可维护性】

1、预编译之后的 SQL 多数情况下可以直接执行,DBMS 不需要再次编译。

2、越复杂的SQL,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。

3、相同的预编译 SQL 可以重复利用。(把一个 SQL 预编译后产生的 PreparedStatement 对象缓存下来,

下次对于同一个 SQL,可以直接使用这个缓存的 PreparedState 对象。)

4、可以将这类SQL语句中的值用占位符替代,不需要每次编译,可以直接执行,

只需执行的时候,直接将每次请求的不同的值设置到占位符的位置。

5、预编译可以视为将sql语句模板化或者说参数化。

5-2.相似功能的代码抽取封装成方法,减少代码冗余

因为不同的数据库会有不同的实现,对数据库的操作一般抽取成接口,在以后的开发中可以降低耦合

5-3.Statement与PreparedStatement区别

【stm主要好处安全,防止非法sQL注入;编译一次,可返回执行多次,效率高】

1.Statement由方法createStatement()创建,该对象用于发送简单的SQL语句

PreparedStatement由方法prepareStatement()创建,该对象用于发送带有一个或者多个输入参数的SQL语句

SQL语句使用“?”作为数据占位符

使用setXxx()方法设置数据

PreparedStatement—预编译

2.效率、性能、开销

3.安全性

4代码可读性

5-4三大对象(接口)

① 连接

Connection

② 命令

父父接口Statement 不推荐使用

父接口PreparedStatement 广泛使用

5-4预编译输入日期时注意事项

1。年月日时 String starttime=input.next();

2.年月日时分秒时格式为Sting endTime=input.nextLine(); //中间有空格,不会换行,

3.为日期赋值时当插入当前时间时外层new java.util.Date,内层new java.sql.Date.然后调用getTime()可以获得当前年月日【时分秒默认都是0】

package cn.kgc.tangcco.test1021;import java.sql.Connection;import java.sql.Date;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Scanner;import com.mysql.cj.util.Util;public class InsertNowTime {public static void main(String[] args) throws SQLException {//声明接口和手动输入关键字;Connection con=null;ResultSet rs=null;PreparedStatement stm=null;try {Class.forName("com.mysql.cj.jdbc.Driver");//2.获得连接con=DriverManager.getConnection("jdbc:mysql:///kgc", "root", "123456");//3.编写sql语句并预编译,执行sqlString sql=" insert into student (student_num,student_name,modify_date ) values (?,?,?)";// stm=con.prepareStatement(sql);//外部导入java.sql.Date.对象;里面导入java.util.Date.对象;获得当前时间;stm.setInt(1, 299);stm.setString(2, "光头强2");stm.setDate(3, new Date(new java.util.Date().getTime()) );//只能返回年月日//4.接收预编译对象的数据并判断是否执行成功int i=stm.executeUpdate();if (i>0) {System.out.println("修改成功");}} catch (Exception e) {e.printStackTrace();}finally {if (rs!=null) {rs.close();}if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}/48/

子接口CallableStatement 调用存储过程使用

③ 结果

增删改:int的行数

查询:表-> ResultSet接口

【模糊查询】

package cn.kgc.tangcco.test1021;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Scanner;public class MoHuChaXun {public static void main(String[] args) throws SQLException {//声明接口和手动输入关键字;Connection con=null;ResultSet rs=null;PreparedStatement stm=null;Scanner input = new Scanner(System.in);System.out.println("请输入要查找的信息");String student_num=input.nextLine();//声明模糊查询的变量student_num="%"+student_num+"%";try {Class.forName("com.mysql.cj.jdbc.Driver");//2.获得连接con=DriverManager.getConnection("jdbc:mysql:///kgc", "root", "123456");//3.编写sql语句并预编译,执行String sql="select from student where student_name like ?";stm=con.prepareStatement(sql);stm.setString(1, student_num);//4.接收预编译对象的数据并遍历rs=stm.executeQuery();while (rs.next()) {System.out.println("学号t学生姓名t密码t性别");System.out.println(rs.getInt(1)+"t"+rs.getString(2)+"t"+rs.getString(3)+"t"+rs.getString(4));}} catch (Exception e) {e.printStackTrace();}finally {if (rs!=null) {rs.close();}if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}/请输入要查找的信息福学号学生姓名密码性别10022孙福祥null/

【更新】更改插入删除

packagecn.kgc.tyl.test1020;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class SelectPreparedStatement {public static void main(String[] args) throws SQLException {PreparedStatement stm=null;Connection con=null;PreparedStatement stm2=null;try {Class.forName("com.mysql.cj.jdbc.Driver");//1.加载驱动con=DriverManager.getConnection("jdbc:mysql:///kgc","root","123456");//2.建立连接String sql = "insert into student (student_num,student_name)values(?,?)";//3.获得预编译对象并给预编译对象赋值String sq2="delete from student where student_name=?";stm = con.prepareStatement(sql);stm.setInt(1, 110);stm.setString(2,"范永光");stm.executeUpdate();//4.执行更新SQL语句stm2=con.prepareStatement(sq2);stm2.setString(1, "远哥");stm2.executeUpdate();} catch (Exception e) {e.printStackTrace();}finally {if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFrdycSv-1604303154966)(JDBC/image-173111564.png)]

package cn.kgc.tyl.test1020;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class UpdatePareparedStatement {public static void main(String[] args) throws SQLException {PreparedStatement stm=null;Connection con=null;try {//1.加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//先mysql再jdbc//2.获得连接con=DriverManager.getConnection("jdbc:mysql:///kgc","root","123456");//先jdbc再mysql//3.进行预编译,并给预编译对象赋值;String sq="update student set student_name=? where student_num=?";stm=con.prepareStatement(sq);stm.setString(1, "范增");stm.setInt(2, 10);//4.执行int i=stm.executeUpdate();if (i>0) {System.out.println("更新成功;");}} catch (Exception e) {e.printStackTrace();}finally {if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}

5-5【批量更新和循环更新】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xz5d9MAw-1604303154968)(JDBC/image-073142446.png)]

5- sql 动态解析

mybatis 在调用 connection 进行 sql 预编译之前,会对sql语句进行动态解析,动态解析主要包含如下的功能:

占位符的处理动态sql的处理参数类型校验

注: mybatis 默认情况下,将对所有的 sql 进行预编译。

6.抽取JDBC工具类 JDBCUtils

【封装工具】

封装把公共的属性方法进行封装,用静态 的类只要加载,就可以执行;

1.三个接口变量,增删改的方法;获得连接方法;释放资源方法【当关闭资源时,有多余的参数用null传递,比如查询方法三个变量

,通用增删改第三个变量就只需要传递为null就可以了】

2.封装时,返回对象尽量用Integer或者Long【数据量上千万条时】。是对象,数量可以为null;

3.可变长数组Object…objects可以代表0-多个对象;

4.Dao包按照实体类分为多个包,【还可以细分为用户模块,订单模块】比如student,teacher然后在各个dao的子包中建立接口类和具体实现类比如

/demo/src/cn/kgc/tangcco/test1022/dao/teacher/impl/TeacherDaoImpl.java;

/demo/src/cn/kgc/tangcco/test1022/dao/student/impl/StudentDaoImpl.java

5.输出语句时,先输出结果,再输出原因【登录失败,密码或用户不正确】

6.dao层连接实体类和工具类,包的作用时安全性和分门别类,把具有不同共同的类放在不同的包中;

7.工具类中方法尽量用trycatch包裹声明异常,否则在在工具类中thorows抛出异常就必须在daoimpl中声明处理异常;那么daoimpl中格式不美观

进行JDBC封装原因:

采用面向接口编程,可以降低代码间的耦合性

具体有三个好处

1.增加可读性;

2.利于代码复用

3.利于后期修改和维护:简化书写

DAO模式优势:隔离了数据访问代码和业务逻辑代码;隔离了不同数据库实现

6-2DAO模式

面向接口编程:只关心类实现的功能,不关心具体实现过程,【实现数据无损替换】

持久化数据存储在dao层,DB【用户请求到右边,DB端dao层返回数据到界面】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W81zUzSA-1604303154968)(JDBC/image-135451856.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ublkuO6h-1604303154969)(JDBC/image-215752147.png)]

实现类实现接口并数据库工具类,此种封装JDBC的结构即为DAO模式
Data Access Object(数据存取对象) 位于业务逻辑和持久化数据之间实现对持久化数据的访问DAO起着转换器的作用,把实体类转换为数据库中的记录

为解决业务代码和数据访问代码的紧耦合给修改和维护代码带来的不便,推荐使用DAO模式封装JDBC

6-3配置文件:

让用户脱离程序本身修改相关的变量设置——使用配置文件

Java中的配置文件常为properties文件后缀为.properties格式是“键=值”格式使用“#”来注释driver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql:///kgcusername=rootpassword=123666

储在MySQL数据库中,但在开发和部署时有可能使用不同的数据库,也可能因为客户的需求而更换数据库产品。

弊端数据库发生改变时,要重新修改代码,重新编译和部署

解决将数据库信息写在配置文件当中,让程序通过读取配置文件来获得这些信息

6-4Java中提供了Properties类来读取配置文件

ResourceBundle rb=ResourceBundle.getBundle(“db”);//直接获得db.properties文件对象;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lJVKsCOK-1604303154970)(JDBC/image-221812503.png)]

6-3-2抽取一个连接对象

需求:不想传递参数(麻烦),还得保证工具类的通用性。

解决:配置文件

jdbc.properties

url=

user=

password=

抽取一个方法释放资源

代码实现:public class JDBCUtils {//封装驱动和连接资源的参数【文件的读取,只需要读取一次即可拿到这些值。使用静态代码块】private static String url, user, password,driver;static{//读取资源文件,获取值。try {​//1. 创建Properties集合类。​Properties pro = new Properties();​//获取src路径下的文件的方式--->ClassLoader 类加载器​ClassLoader classLoader = JDBCUtils.class.getClassLoader();【通过class对象获得字节码加载器对象】​URL res = classLoader.getResource("jdbc.properties");//inputStream in=classloader.getResourceAsStream("jdbc.properties");【通过类加载方法获得输入流】​String path = res.getPath();​System.out.println(path);///D:/IdeaProjects/hou/out/production/day04_jdbc/jdbc.properties​//2. 加载文件//pro.load(in);​// pro.load(new FileReader("D:IdeaProjectshouday04_jdbcsrcjdbc.properties"));​pro.load(new FileReader(path));​//3. 获取数据,赋值​url = pro.getProperty("url");​user = pro.getProperty("user");​password = pro.getProperty("password");​driver = pro.getProperty("driver");​//4. 注册驱动​Class.forName(driver);} catch (IOException e) {​e.printStackTrace();} catch (ClassNotFoundException e) {​e.printStackTrace();}}//M1获取连接public static Connection getConnection() throws SQLException {return DriverManager.getConnection(url, user, password);}//M2增删改释放资源:public static void close(Statement stmt,Connection conn)throws Exception{if( stmt != null){ stmt.close(); }if( conn != null){ conn.close(); }}//M3.查询释放资源public static void close(ResultSet rs,Statement stmt, Connection conn){if( rs != null){ rs.close(); }if( stmt != null){ stmt.close();}if( conn != null){ conn.close();}}}}

通过键盘录入用户名和密码

判断用户是否登录成功

select from user where username = “” and password = “”;

如果这个sql有查询结果,则成功,反之,则失败

步骤:1. 创建数据库表 userCREATE TABLE USER(id INT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(32),PASSWORD VARCHAR(32));INSERT INTO USER VALUES(NULL,'zhangsan','123');INSERT INTO USER VALUES(NULL,'lisi','234');2. 代码实现:public class JDBCDemo9 {public static void main(String[] args) {//1.键盘录入,接受用户名和密码Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();//2.调用方法boolean flag = new JDBCDemo9().login(username, password);//3.判断结果,输出不同语句if(flag){​//登录成功​System.out.println("登录成功!");}else{​System.out.println("用户名或密码错误!");}​ }public boolean login(String username ,String password){if(username == null || password == null){​return false;}//连接数据库判断是否登录成功Connection conn = null;Statement stmt = null;ResultSet rs = null;//1.获取连接try {​ conn = JDBCUtils.getConnection();​//2.定义sql​String sql = "select from user where username = '"+username+"' and password = '"+password+"' ";​//3.获取执行sql的对象​stmt = conn.createStatement();​//4.执行查询​rs = stmt.executeQuery(sql);​//5.判断​/ if(rs.next()){//如果有下一行,则返回true​ return true;​}else{​ rturn false;​}/​return rs.next();//如果有下一行,则返回true} catch (SQLException e) {​e.printStackTrace();}finally {​JDBCUtils.close(rs,stmt,conn);}return false;}}

7.JDBC控制事务

事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

操作: 1. 开启事务 2. 提交事务 3. 回滚事务

使用Connection对象来管理事务

开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务

在执行sql之前开启事务 提交事务:commit() 当所有sql都执行完提交事务

回滚事务:rollback() 在catch中回滚事务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-065NwI33-1604303154970)(JDBC/image-231327127.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hyGMHKt1-1604303154971)(JDBC/image-184000064.png)]

Connection conn = null;PreparedStatement pstmt1 = null;PreparedStatement pstmt2 = null;try {//1.获取连接conn = JDBCUtils.getConnection();//开启事务conn.setAutoCommit(false);//2.定义sql//2.1 张三 - 500String sql1 = "update account set balance = balance - ? where id = ?";//2.2 李四 + 500String sql2 = "update account set balance = balance + ? where id = ?";//3.获取执行sql对象pstmt1 = conn.prepareStatement(sql1);pstmt2 = conn.prepareStatement(sql2);//4. 设置参数pstmt1.setDouble(1,500);pstmt1.setInt(2,1);pstmt2.setDouble(1,500);pstmt2.setInt(2,2);//5.执行sqlpstmt1.executeUpdate();// 手动制造异常int i = 3/0;pstmt2.executeUpdate();//提交事务mit();} catch (Exception e) {//事务回滚try {if(conn != null) {conn.rollback();}} catch (SQLException e1) {e1.printStackTrace();}e.printStackTrace();}finally {JDBCUtils.close(pstmt1,conn);JDBCUtils.close(pstmt2,null);}}}

8.数据库连接池

.数据库连接池负责分配**,【管理和释放】数据库连接,**它允许应用程序【重复使用】一个现有的

数据库连接**,**而不是重新建立一个

数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数

据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.

连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数

超过最大连接数量时,这些请求将被加入到【等待队列】中.

数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:

\1. 最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有

大量的数据库连接资源被浪费.

\2. 最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将

被加入到等待队列中,这会影响【以后的数据库操作】

\3. 如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接

请求等价于建立一个新的数据库连接.不过,这些大于最小连接数的数据库连接在使用完【不会马上被

释放】,他将被放到连接池中等待【重复使用或是空间超时后】被释放.

JDBC : JDBC Template

数据库连接池

概念:其实就是一个容器(集合),存放数据库连接的容器。

当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

好处:1. 节约资源2. 用户访问高效

实现:

标准接口:DataSource javax.sql包下的

方法:

获取连接:getConnection() 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

一般我们不去实现它,有数据库厂商来实现

C3P0:数据库连接池技术

Druid:数据库连接池实现技术,由阿里巴巴提供的

8-1.C3P0:数据库连接池技术

步骤:

导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,

不要忘记导入数据库驱动jar包java .connector.jar

定义配置文件:

名称: c3p0.properties 或者 c3p0-config.xml

路径:直接将文件放在src目录下即可。

创建核心对象 数据库连接池对象 ComboPooledDataSource

获取连接: getConnection

//1.创建数据库连接池对象DataSource ds = new ComboPooledDataSource(); //2. 获取连接对象Connection conn = ds.getConnection();

8-2 Druid:数据库连接池实现技术,由阿里巴巴提供的

步骤:

导入jar包 druid-1.0.9.jar

定义配置文件:

是properties形式的 可以叫任意名称,可以放在任意目录下3. 加载配置文件。Properties

获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory

//3.加载配置文件Properties pro = new Properties();InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");pro.load(is);//4.获取连接池对象DataSource ds = DruidDataSourceFactory.createDataSource(pro);

//5.获取连接

Connection conn = ds.getConnection();

定义工具类

8-3. 定义一个类 DBUtils【DruidDataSourceFactory】

提供静态代码块加载配置文件,初始化连接池对象

提供方法

获取连接方法:通过数据库连接池获取连接

释放资源

获取连接池的方法

public class JDBCUtils {//1.定义成员变量 DataSourceprivate static DataSource ds ;static{try {//1.加载配置文件​Properties pro = new Properties(); pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));​//2.获取DataSource​ds = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {​e.printStackTrace();} }M1:获取连接public static Connection getConnection() throws SQLException {return ds.getConnection();}//M2增删改释放资源:public static void close(Statement stmt,Connection conn)throws Exception{if( stmt != null){stmt.close(); }if( conn != null){conn.close(); }}//M3.查询释放资源public static void close(ResultSet rs,Statement stmt, Connection conn){if( rs != null){rs.close(); }if( stmt != null){stmt.close();}if( conn != null){conn.close();}//归还连接}//M4 获取连接池方法 public static DataSource getDataSource(){return ds; }}

8-4Spring JDBC

Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发

步骤:

导入jar包

创建JdbcTemplate对象。依赖于数据源DataSource

JdbcTemplate template = new JdbcTemplate(ds);

调用JdbcTemplate的方法来完成CRUD的操作

update():执行DML语句。增、删、改语句

queryForMap():[结果集长度只能是1]

查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合

注意:这个方法查询的结果集长度只能是1

queryForList():查询结果将结果集封装为list集合

注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中

query():查询结果,将结果封装为JavaBean对象

query的参数:RowMapper

一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装

new BeanPropertyRowMapper<类型>(类型.class)

queryForObject:查询结果,将结果封装为对象

一般用于聚合函数的查询

练习:

需求:1. 修改1号数据的 salary 为 10000

添加一条记录

删除刚才添加的记录

查询id为1的记录,将其封装为Map集合

查询所有记录,将其封装为List

查询所有记录,将其封装为Emp对象的List集合

查询总记录数

import cn.hou.domain.Emp;import cn.hou.utils.JDBCUtils;import org.junit.Test;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import java.sql.Date;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;import java.util.Map;public class JdbcTemplateDemo2 {//Junit单元测试,可以让方法独立执行​//. 获取JDBCTemplate对象private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());1. 修改1号数据的 salary 为 10000@Testpublic void test1(){//提供SQL语句并执行【更改比较特殊】String sql = "update emp set salary = 10000 where id = 1001";​ int count = template.update(sql);​ System.out.println(count);}// 2. 添加一条记录@Testpublic void test2(){String sql = "insert into emp(id,ename,dept_id) values(?,?,?)"; int count = template.update(sql, 1015, "郭靖", 10); System.out.println(count); }//3.删除刚才添加的记录@Testpublic void test3(){​ String sql = "delete from emp where id = ?";​ int count = template.update(sql, 1015);​ System.out.println(count);}//4.查询id为1001的记录,将其封装为Map集合注意:这个方法查询的结果集长度只能是1@Testpublic void test4(){​ String sql = "select from emp where id = ? or id = ?";​ Map<String, Object> map = template.queryForMap(sql, 1001,1002);​ System.out.println(map);//输出结果为 {id=1001, ename=孙悟空, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=20}}// 5. 查询所有记录,将其封装为List@Testpublic void test5(){​ String sql = "select from emp";​ List<Map<String, Object>> list = template.queryForList(sql);​ for (Map<String, Object> stringObjectMap : list) {​System.out.println(stringObjectMap);​ }}​ //6. 查询所有记录,将其封装为Emp对象的List集合@Testpublic void test6(){​ String sql = "select from emp";​ List<Emp> list = template.query(sql, new RowMapper<Emp>() {​@Override​public Emp mapRow(ResultSet rs, int i) throws SQLException {​ Emp emp = new Emp();​ int id = rs.getInt("id");​ String ename = rs.getString("ename");​ int job_id = rs.getInt("job_id");​ int mgr = rs.getInt("mgr");​ Date joindate = rs.getDate("joindate");​ double salary = rs.getDouble("salary");​ double bonus = rs.getDouble("bonus");​ int dept_id = rs.getInt("dept_id");​ emp.setId(id);​ emp.setEname(ename);​ emp.setJob_id(job_id);​ emp.setMgr(mgr);​ emp.setJoindate(joindate);​ emp.setSalary(salary);​ emp.setBonus(bonus);​ emp.setDept_id(dept_id);​ return emp;​}​ });​ for (Emp emp : list) {​System.out.println(emp); }}//6. 查询所有记录,将其封装为Emp对象的List集合@Testpublic void test6_2(){​ String sql = "select from emp";​ List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));​ for (Emp emp : list) {​System.out.println(emp);​ }}// 7. 【查询总记录数】@Testpublic void test7(){​ String sql = "select count(id) from emp";​ Long total = template.queryForObject(sql, Long.class);​ System.out.println(total);}}

9. 普通的增删查改

3.1 创建一个类customer

public class Customer {private int id;private String name;private String email;private Date birth;public Customer() {super();}public Customer(int id, String name, String email, Date birth) {super();this.id = id;this.name = name;this.email = email;this.birth = birth;}

3.2 创建jdbc连接,并封装为方法

// 获取数据库的连接public static Connection getConnection() {Connection connection = null;InputStream is = null;try {is = JDBCUtils.class.getClassLoader().getResourceAsStream("sqlDriver.properties");Properties ps = new Properties();ps.load(is);String user = ps.getProperty("user");String password = ps.getProperty("password");String driverClass = ps.getProperty("driverClass");String url = ps.getProperty("url");// 创建Driver对象Class clazz = Class.forName(driverClass);Object obj = clazz.newInstance();Driver driver = (Driver) obj;// 注册驱动DriverManager.registerDriver(driver);connection = DriverManager.getConnection(url, user, password);} catch (Exception e) {e.printStackTrace();} finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return connection;}

3.3 在操作完成后要进行连接的关闭

public static void close(Connection connection, PreparedStatement ps) {if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException e) {e.printStackTrace();}}}public static void close(Connection connection, PreparedStatement ps, ResultSet rs) {close(connection,ps);if(rs != null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}}

3.4 增删查改操作

// 对数据库的 增 ,删,改,查public class CRUDTest {// 从数据库中查找一条数据@Testpublic void select() throws Exception {Customer customer = getCustomerById();System.out.println(customer);List<Customer> customers = getCustomers();for (Customer customer2 : customers) {System.out.println(customer2);}}// 查询多条数据public List<Customer> getCustomers() throws Exception {Connection connection = JDBCUtils.getConnection();String sql = "select from customers";// 2.预编译 -- 如果没有占位符可以不填充数据PreparedStatement ps = connection.prepareStatement(sql);// 4.执行sql语句ResultSet rs = ps.executeQuery(); // 查找的结果都已经放到ResultSet中了List<Customer> list = new ArrayList<>();while(rs.next()){int id = rs.getInt("id");String name = rs.getString("name");String email = rs.getString("email");Date birth = rs.getDate("birth");//将每条数据放入集合中list.add(new Customer(id, name, email, birth));}// 6.关闭资源JDBCUtils.close(connection, ps, rs);return list;}//查询一条数据public Customer getCustomerById() throws Exception {Connection connection = JDBCUtils.getConnection();String sql = "select from customers where id = ?";// 2.预编译PreparedStatement ps = connection.prepareStatement(sql);// 3.填充数据ps.setInt(1, 20);// 4.执行sql语句ResultSet rs = ps.executeQuery(); // 查找的结果都已经放到ResultSet中了Customer customer = null;// 5.取数据【根据下标或者字符段名称】if (rs.next()) {// 如果有数据就返回true,根据列的索引获取对应的列上的值// int id = rs.getInt(1); // String name = rs.getString(2);// String email = rs.getString(3);// Date date = rs.getDate(4);// 获取列上值的第二种方式int id = rs.getInt("id");String name = rs.getString("name");String email = rs.getString("email");Date birth = rs.getDate("birth");【// 考虑将数据进行封装】customer = new Customer(id, name, email, birth);// 输出获取到的内容System.out.println(id + " " + name + " " + email + " " + birth);}// 6.关闭资源JDBCUtils.close(connection, ps, rs);return customer;}//向数据库中插入一条数据@Testpublic void insert() {//多个方法作为局部变量单独声明Connection connection = null;PreparedStatement ps = null;try {// 1 : 连接数据库connection = JDBCUtils.getConnection();// sql语句String sql = "INSERT INTO customers(NAME,email,birth) " + "VALUES(?,?,?);";// 2.预编译ps = connection.prepareStatement(sql);// 3.设置内容ps.setString(1, "强哥"); // 第一个参数:第几个问号 第二个参数:内容ps.setString(2, "qiangge@");// 获取一个sql下的DateDate date = new Date(new java.util.Date().getTime());ps.setDate(3, date);// 4.执行sql语句ps.execute(); // 如果是查询语句返回true//或者int i=ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {// 5.关闭资源JDBCUtils.close(connection, ps);}}//删除一条件数@Testpublic void delete() throws Exception {// 1. 获取数据库的连接Connection connection = JDBCUtils.getConnection();String sql = "DELETE FROM customers WHERE id = ?";// 2. 预编译PreparedStatement ps = connection.prepareStatement(sql);// 3.填充数据ps.setInt(1, 19);// 4.执行sql语句int executeUpdate = ps.executeUpdate();System.out.println(executeUpdate + "条受到影响");// 5.关闭资源JDBCUtils.close(connection, ps);}//修改一条件数@Testpublic void update() throws Exception {Connection connection = null;PreparedStatement ps = null;try {connection = JDBCUtils.getConnection();String sql = "UPDATE customers SET NAME = ? WHERE id = ?";ps = connection.prepareStatement(sql);ps.setString(1, "成哥");ps.setInt(2, 18);int executeUpdate = ps.executeUpdate();System.out.println(executeUpdate + "条数据受到影响");} catch (Exception e) {e.printStackTrace();} finally {JDBCUtils.close(connection, ps);}}}

10.通用增删查改CRUD【create,read,update,delete】

【获得表结构】getMetaData()

1、使用rs.getMetaData().getTableName(1))就可以返回表名

2、rs.getMetaData().getColumnCount()字段数

3、rs.getMetaData().getColumnName(i));字段名

创建类 User.java

public class User {private int id;private String name;private String address;private String phone;

4.1 创建通用连接方案 - 通用增删改

// 通用的增删改public static int UID(String sql,Object ...objects) {Connection connection = null;PreparedStatement ps = null;int executeUpdate = -1;try {connection = JDBCUtils.getConnection();ps = connection.prepareStatement(sql);for (int i = 0; i < objects.length; i++) {// i 表示索引ps.setObject(i + 1, objects[i]); // i + 1表示的是第几个占位符}executeUpdate = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();}finally{JDBCUtils.close(connection, ps);}return executeUpdate;}

测试代码:

// 测试通用的增删改@Testpublic void insert(){String sql = "INSERT INTO customers(NAME,email,birth) VALUES(?,?,?)";Date date = new java.sql.Date(new java.util.Date().getTime());int uid = JDBCUtils.UID(sql, "强哥","qiangge@",date);System.out.println(uid + "条数据受到影响");}

4.2 通用查找(一条或多条)

只查一条数据:

// 通用的查找 (只有一条数据)Class<T> clazz : 运行时类的对象public static <T> T getObject(Class<T> clazz,String sql,Object ...objects) throws Exception{Connection connection = JDBCUtils.getConnection();PreparedStatement ps = connection.prepareStatement(sql);for (int i = 0; i < objects.length; i++) {ps.setObject(i + 1, objects[i]);}//4.执行sql语句ResultSet rs = ps.executeQuery();//获取列的数量int columnCount = rs.getMetaData().getColumnCount();//创建对象T t = clazz.newInstance();while(rs.next()){//遍历每一条数据for (int i = 0; i < columnCount; i++) {//获取某列的列名(如果有别名获取的是别名)String columnLabel = rs.getMetaData().getColumnLabel(i + 1) //通过列名获取列中的数据。Object value = rs.getObject(rs.getMetaData().getColumnLabel(i + 1));//封装//通过反射 - 给对象中的属性进行赋值//将表中的列名当作类中的属性名。如果列名和属性名不一样,可以通过别名的方式(别名 = 属性名)//通过列名就获取到了类中的对应的属性Field declaredField = clazz.getDeclaredField(columnLabel);declaredField.setAccessible(true);// 第一个参数 : 是给哪个对象进行赋值// 第二个参数 : 属性值declaredField.set(t, value);}}//关闭资源BCUtils.close(connection, ps, rs);return t;}

查多条数据:

// 通用的查找 (返回多条数据)public static <T> List<T> getObjects(Class<T> clazz,String sql,Object ...objects) throws Exception{//1.获取数据库的连接Connection connection = JDBCUtils.getConnection();//2.预编译PreparedStatement ps = connection.prepareStatement(sql);//3.填充数据for (int i = 0; i < objects.length; i++) {ps.setObject(i + 1, objects[i]);}//4.执行sql语句ResultSet rs = ps.executeQuery();ResultSetMetaData md = rs.getMetaData(); //获取元数据。//获取列的数量int columnCount = md.getColumnCount();//创建一个集合List<T> list = new ArrayList<>();while(rs.next()){//遍历每一条数据//创建对象T t = clazz.newInstance();// 第一个问题 : 如何获取到表的列数// 第二个问题 : 需要知道类中的属性// 第三个问题 : 对象中属性的名字怎么来for (int i = 0; i < columnCount; i++) {//获取某列的列名(如果有别名获取的是别名)String columnLabel = md.getColumnLabel(i + 1); //通过列名获取列中的数据。Object value = rs.getObject(columnLabel);//封装//通过反射 - 给对象中的属性进行赋值//将表中的列名当作类中的属性名。如果列名和属性名不一样,可以通过别名的方式(别名 = 属性名)//通过列名就获取到了类中的对应的属性Field declaredField = clazz.getDeclaredField(columnLabel);declaredField.setAccessible(true);第一个参数 : 是给哪个对象进行赋值第二个参数 : 属性值declaredField.set(t, value);}//将对象放入到集合中list.add(t);}//关闭资源JDBCUtils.close(connection, ps, rs);return list;}

测试代码:

String sql = "select id,name,email,birth from customers where id = ?";Customer customer = getObject(Customer.class, sql, 5);System.out.println(customer);sql = "select from users where id = ?";User object = getObject(User.class, sql, 1);System.out.println(object);sql = "select from users";List<User> users = getObjects(User.class, sql);for (User user : users) {System.out.println(user);}

11.持久化

将程序中的数据在瞬时状态和持久状态间转换的机制即为数据持久化

12.单例模式【含饿汉模式懒汉模式】

12-1单例模式

系统运行期间,有且仅有一个实例

一个类只有一个实例——最基本的要求

只提供私有构造器;它必须自行创建这个实例

定义了静态的该类私有对象;它必须自行向整个系统提供这个实例

提供一个静态的公有方法,返回创建或者获取本身的静态私有对象

若在并发,它严重的弊端,线程不安全,很有可能会出现多个configManager实例,所以在实际开发应用中并不会使用上述方式来实现单例

12-2饿汉懒汉模式

13.登录:

通过预编译对象查询到用户名是否存在,然后通过结果集获得密码,如果密码匹配则登录成功。否则密码不正确,登陆失败

13-1流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-laWMR7Kg-1604303154971)(JDBC/image-094143479.png)]

package cn.kgc.tangcco.test1021;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Scanner;public class TestLogin {public static void main(String[] args) throws SQLException {Scanner input = new Scanner(System.in);System.out.println("请输入用户名");String userName=input.next();System.out.println("请输入密码");String userPwd=input.next();Connection con=null;PreparedStatement stm=null;ResultSet rs=null;try {//1.连接驱动Class.forName("com.mysql.cj.jdbc.Driver");//2.获得连接con=DriverManager.getConnection("jdbc:mysql:///kgc?useUnicode=true&characterEncoding=utf-8", "root", "123456");//3.写sql语句,预编译,并执行sql语句String sql="select from student where student_name=?";stm=con.prepareStatement(sql);stm.setString(1, userName);rs=stm.executeQuery();//4.执行;booleanexistsUserName=false;String pwd=null;while (rs.next()) {existsUserName=true;pwd=rs.getString("login_password");}if (existsUserName) {if (pwd.equals(userPwd)) {System.out.println("登录成功,欢迎"+userName);}else {System.out.println("密码或账号不正确");}}else {System.out.println("密码或账号不正确");}} catch (Exception e) {e.printStackTrace();}finally {if (rs!=null) {rs.close();}if (stm!=null) {stm.close();}if (con!=null) {con.close();}}}}/请输入用户名孙福祥请输入密码22登录成功,欢迎孙福祥/

14安全套接字协议SSL与HTTPS

随着互联网的发展,给我们的生活带来便利的同时,也伴随着很多网络钓鱼、信息泄露、网络诈骗等事件的频繁发生,企业网站被钓鱼网站仿冒,遭受经济损失,影响品牌形象。

如果网站不使用SSL证书,数据以HTTP明文传输,极容易被第三方监听、截取和篡改,而导致用户信息被泄露,给在线用户带来直接损失。

而部署SSL证书后能确保信息传输的安全性,可防止信息泄露。

14-1、SSL(安全套接字层)

SSL(Secure Sockets Layer安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层与应用层之间对网络连接进行加密。

SSL证书是数字证书(数字证书包括:SSL证书、客户端证书、代码签名证书等)的一种,因为配置在服务器上也称为服务器SSL证书。SSL证书就是遵守SSL协议,由受信任的数字证书颁发机构CA(如:沃通CA)在验证服务器身份后颁发的一种数字证书。

使用SSL证书的优势:

· SSL证书用于实现数据加密传输,防止数据被泄露和篡改

· 用于认证服务器身份,防范被钓鱼网站攻击

· 用于消除浏览器地址栏发出的“不安全”的警告

· 提高SEO搜索引擎排名

· 提升用户对网站的信任

· 有助于提高网站的在线销售业绩

网站加密算法RSA,DSA,ECDSA;

14-2、HTTPS(安全超文本传输协议)

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL层,HTTPS的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与TCP之间)。这个系统提供了身份验证与加密通讯方法。

网站使用HTTPS的原因有很多:

· HTTPS有助于在服务器和浏览器之间建立安全通信

· 它可以保护网站免受篡改或窃听

· 它可以保护用户免受中间人攻击

· 各大主流浏览器纷纷要求网站从HTTP升级HTTPS访问

· 它广泛地被银行、医疗、电子商务、社交媒体和政府等行业使用

三、SSL证书申请

安全可信的SSL证书需要向CA机构(证书授权颁发中心)申请,通过严格的审查后才给予颁发。

如果是个人网站,建议选择DVSSL证书。申请者只需要验证域名管理权,10-50分钟颁发,无需递交纸质文件,也不需要确认申请者单位身份,是一种非常经济的 SSL证书!

如果是中小型企业网站、电子商务网站,建议选择OVSSL证书。申请者需要通过证书颁发机构的审核。审核内容包括企业身份和域名所有权,以证明申请单位是一个合法存在的真实主体,CA机构将在人工核实后签发证书。

EVSSL 证书具有最高级别可信度及安全性,需要通过极其严格的审核。审核内容包括企业身份,地址,电话等信息的真实性,以及域名所有权,确保网站身份的真实可靠,是访问者最值得信赖的 SSL 证书。这种证书能在浏览器地址栏显示公司名称,从而使访问者更加放心相信他们所进行交易的网站是真实合法的,提升在线交易量。

!完成SSL证书的申请和安装流程。您可以访问SSL盾官网,选择SSL证书类型和品牌,自助申请,完成域名验证,等待审核通过即可下载SSL证书,最后安装部署到服务器上即可。【ssl证书作用个人信息,支付安全,私密信息,交易数据】

15.三层架构【实体类作为参数贯穿于三层,不属于任何一层】

【业务逻辑层 Business Logic LayeDAL 是数据访问层 Data Access Layer用户界面(User Interface) 】

1、【实体类user】作为参数贯穿于三层之间;

2、通过传参、方法调用来实现功能;

3、各层之间各负其责;互不影响

15-1三层架构定义

就是为了符合“高内聚,低耦合”思想,把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构,各层之间采用接口相互访问,并通过对象模型的实体类(Model)作为数据传递的载体,不同的对象模型的实体类一般对应于数据库的不同表,实体类的属性与数据库表的字段名一致。 [1]

15-2三层架构区分层次的目的

是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工

15-3各层定义

UI(表现层):【与用户交互、展示数据】 主要是指与用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数据。

界面交互设计的原则统一性原则界面风格统一用相同方式展现相同类型的数据,如:日期类型交互风格统一用相同方式完成相同类型的操作,如:录入日期美观性原则界面美观大方易用性原则操作方式自然、易理解

BLL:(业务逻辑层):【控制业务流程及事务】UI层和DAL层之间的桥梁。实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等。

DAL:(数据访问层):【实现数据库操作】 与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(当然这些操作都是基于UI层的。用户的需求反映给界面(UI),UI反映给BLL,BLL反映给DAL,DAL进行数据的操作,操作后再一一返回,直到将用户所需数据反馈给用户

**【Entity(实体层):**它不属于三层中的任何一层,但是它是必不可少的一层。】

15-4Entity在三层架构中的作用:

1、实现面向对象思想中的"封装";2、贯穿于三层,在三层之间传递数据;(注:确切的说实体层贯穿于三层之间,来连接三层)3、对于初学者来说,可以这样理解:每张数据表对应一个实体,即每个数据表中的字段对应实体中的属性(注:当然,事实上不是这样。为什么?1>,可能我们需要的实体在数据表对应的实体中并不存在;2>,我们完全可以将所有数据表中的所有字段都放在一个实体里)4、每一层(UI—>BLL—>DAL)之间的数据传递(单向)是靠变量或实体作为参数来传递的,这样就构造了三层之间的联系,完成了功能的实现。

15-5三层架构的优劣势

三层架构的优势:

1,结构清晰、耦合度低2,可维护性高,可扩展性高3,利于开发任务同步进行, 容易适应需求变化

三层架构的优劣势:

1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码

3、增加了代码量,增加了工作量

15-6分层的特点及原则

分层的特点

每一层都有自己的职责分层结构中,不同层之间通过【实体类】传输数据

上一层不用关心下一层的实现细节,上一层通过下一层提供的对外接口来使用其功能

上一层调用下一层的功能,下一层不能调用上一层功能

分层原则1——【顺序访问原则】下一层为上一层服务,但不使用上层的服务

分层原则2——【封装性】原则 每个层次向外【公开接口】,但是隐藏内部细节

面向接口编程:只关系实现的功能,不关心具体的实现细节

分层开发的优势

代码复用

职责清晰,分工明确,分离开发人员的关注

无损替换【工具类之间切换,比如MySQL,切换成Oracle;当前层替换】

降低了系统间的依赖利于维护扩展

16.JDBCUtils工具类和DBUtils工具类不同点【其实两者没有区别,可以自己自定义是否进行加载配置文件或c3p0使用连接池】也可以封装进去BaseDao

dbutils 封装了driver,url,root,pwd运用的是 连接池工具,或者properies配置文件;使用了数据连接池;

不用专门关闭资源,只是归还连接;

BaseDao中工具都是私有的静态的。

1.7版本以后有个直接获得配置文件的方法,不用输出流

package cn.kgc.tangyingli.utils;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ResourceBundle;/***工具类* */public class DBUtil {static Connection con= null;static PreparedStatement stm=null;static ResultSet rs=null;//获得连接方法ResourceBundle rb=ResourceBundle.getBundle("db");//直接获得db.properties文件对象;public static Connection getConnection() {try {Class.forName("com.mysql.cj.jdbc.Driver");con=DriverManager.getConnection("jdbc:/mysql:///kgc&useSSL=true", "root", "123456");} catch (Exception e) {e.printStackTrace();}return con;}//关闭资源方法public static void releaseResources(Connection con,ResultSet rs,PreparedStatement stm) {try {if (rs!=null) {rs.close();}if (stm!=null) {stm.close();}if (con!=null) {con.close();}} catch (Exception e) {e.printStackTrace();}}//增删改通用方法public static int update(String sql, Object...objects) {con=getConnection();int result=0;try {stm=con.prepareStatement(sql);if (objects!=null) {for (int i = 0; i < objects.length; i++) {stm.setObject(i+1, objects[i]);}}result=stm.executeUpdate();} catch (SQLException e) {e.printStackTrace();}finally {releaseResources(con, null, stm);}return result;}}

封装jdbc工具时,增删改通用方法可以返回值改为布尔类型,那么,查询的方法只需要多加一句用结果集接收即可

17三大连接池

17-1properties创建方法

**方法一、**eclipse 方法: 打开file–new–other 选择general–file–next 在file name后输入:文件名.properties,finish即可。

**方法二、**新建普通的文本文件,然后修改后缀为properties即可创建。

**方法三、**如果是编程实现的话,使用输出流,输出保存时后缀文件是properties即可配置文件

使用c3p0连接池时ssl安全套字协议必须默认为false。【配置文件用连接池时用true/false均可】

使用配置文件原因,解耦合

数据库工作累,封装了jdbc操作的常用功能;

数据库的相关信息是写在源文件中的,如果我们要修改数据库,就必须要切换源码,;我们应该降低代码的耦合度,源代码一点都不需要改动;

配置文件一定要放在src文件夹下面,里面是常量,每个常量的内容后面不能加空格或者引号;

【ResourceBundle】资源包

ResourceBundle rb=ResourceBundle.getBundle(“db”);//直接获得db.properties文件对象;【相当于25-33行的代码】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tiPhnh19-1604303154972)(JDBC/image-36991.png)]

useSSL=true&verifyServerCertificate=false

17-2MySQL在高版本需要指明是否进行SSL连接。

SSL协议提供服务主要: 1)认证用户服务器,确保数据发送到正确的服务器; .2)加密数据,防止数据传输途中被窃取使用;3)维护数据完整性,验证数据在传输过程中是否丢失;当前支持SSL协议两层:SSL记录协议(SSL【Record 】Protocol):建立靠传输协议(TCP)高层协议提供数据封装、压缩、加密等基本功能支持SSL握手协议(SSL 【Handshake】 Protocol):建立SSL记录协议用于实际数据传输始前通讯双进行身份认证、协商加密算法、 交换加密密钥等。

在mysql连接字符串url中加入ssl=true或者false即可

c3p0dbcp****区别

dbcp没有自动回收空闲连接的功能

c3p0有自动回收空闲连接功能

#propertiesdriver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://localhost:3306/kgc? useUnicode=true&characterEncoding=utf8&useSSL=false;com.mysql.username=rootcom.mysql.password=123456

<?xml version="1.0" encoding="UTF-8"?><c3p0-config><default-config><!-- 必填 --><!-- 驱动类 --><property name="driver">com.mysql.jdbc.Driver</property><!-- URL --><property name="url">jdbc:mysql://localhost:3306/kgc? useUnicode=true&characterEncoding=utf8&useSSL=false</property><!-- 账号 --><property name="user">root</property><!-- 密码 --><property name="password">root</property><!-- 可选 --><!-- 初始连接数 --><property name="initialPoolSize">10</property><!-- 最大闲置时间 --><property name="maxIdleTime">30</property><!-- 最大连接数 --><property name="maxPoolSize">100</property><!-- 最小连接数 --><property name="minPoolSize">10</property><!-- 最大SQL语句数 --><property name="maxStatements">200</property></default-config></c3p0-config>

17-3c3p0,dbcp,druid深入了解

1)DBCPDBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序中使用,Tomcat的数据源使用的就是DBCP。2)c3p0c3p0是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。3)Druid阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个 SQL Parser。支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。简单SQL语句用时10微秒以内,复杂SQL用时30微秒。通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。

基本配置是指连接池进行数据库连接的四个基本必需配置:

传递给JDBC驱动的用于连接数据库的用户名、密码、URL以及驱动类名。

17-4DBCP 属性说明表**

17-5C3P0 属性说明表

17-6DRUID 属性说明表

18元数据

简介:metadata一般指元数据。元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能按应用包括数据结构:数据集的名称、关系、字段、约束等;

//列的名称String columnName = rs_metaData.getColumnName(i + 1);// 获取每一行的每一列的值Object columnValue = rs.getObject(columnName);

package com;import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;public class testMatadata {public static void main(String[] args) {Connection conn=null;//1. JDBC连接MYSQL的代码很标准。 String DRIVER="com.mysql.jdbc.Driver";String URL="jdbc:mysql://127.0.0.1:3306/test";String USER="root";String PASSWORD="root";try {//1.加载驱动程序Class.forName(DRIVER);//2.获得数据库链接conn=DriverManager.getConnection(URL, USER, PASSWORD);DatabaseMetaData dbmd = conn.getMetaData(); ResultSet rs = null; System.out.println("数据库已知的用户: "+ dbmd.getUserName());System.out.println("数据库的系统函数的逗号分隔列表: "+ dbmd.getSystemFunctions());System.out.println("数据库的时间和日期函数的逗号分隔列表: "+ dbmd.getTimeDateFunctions());System.out.println("数据库的字符串函数的逗号分隔列表: "+ dbmd.getStringFunctions());System.out.println("数据库供应商用于 'schema' 的首选术语: "+ dbmd.getSchemaTerm());System.out.println("数据库URL: " + dbmd.getURL());System.out.println("是否允许只读:" + dbmd.isReadOnly());System.out.println("数据库的产品名称:" + dbmd.getDatabaseProductName());System.out.println("数据库的版本:" + dbmd.getDatabaseProductVersion());System.out.println("驱动程序的名称:" + dbmd.getDriverName());System.out.println("驱动程序的版本:" + dbmd.getDriverVersion()); System.out.println("数据库中使用的表类型");rs = dbmd.getTableTypes();while (rs.next()) {System.out.println(rs.getString("TABLE_TYPE"));}// 获取连接PreparedStatement pstmt = conn.prepareStatement("select * from test.user ");rs = pstmt.executeQuery();// 得到结果集元数据//目标:通过结果集元数据,得到列的名称ResultSetMetaData rs_metaData = rs.getMetaData();while (rs.next()) {int count = rs_metaData.getColumnCount();for (int i=0; i<count; i++) {// 得到列的名称String columnName = rs_metaData.getColumnName(i + 1);// 获取每一行的每一列的值Object columnValue = rs.getObject(columnName); System.out.print(columnName + "=" + columnValue + ",\n");}}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} }}*****************************************88888数据库已知的用户: root@localhost数据库的系统函数的逗号分隔列表: DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION数据库的时间和日期函数的逗号分隔列表: DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,SEC_TO_TIME,TIME_TO_SEC数据库的字符串函数的逗号分隔列表: ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER数据库供应商用于 'schema' 的首选术语: 数据库URL: jdbc:mysql://127.0.0.1:3306/test是否允许只读:false数据库的产品名称:MySQL数据库的版本:5.7.26-log驱动程序的名称:MySQL Connector Java驱动程序的版本:mysql-connector-java-5.1.32 ( Revision: jess.balint@-0716155848-mlwabor66widht1n )数据库中使用的表类型:LOCAL TEMPORARYSYSTEM TABLESYSTEM VIEWTABLEVIEWuser_id=1,user_name=fanny,

19.面向对象补充【通过接口降低耦合性】

一个类成为另外一个类的属性,这种关系成为合成/聚合关系,此时其中一个类是另外一个类的一部分;一个类成为另外一个类的方法或参数类型,这种关系称为依赖。【不能写人依赖于迈腾,这样代码写死,耦合度太高】Person p=new Person();Office o=new office();Car car=o.getCar("ceo");//返回一个具体的对象,并实现了car接口;【我们不知道具体哪个类,但是代码能运行,代码耦合性降低了】p.driver(car);多态:用接口或父类声明引用指向实现类或具体子类对象【父类引用指向子类】,动态绑定;封装jdbc工具是,用常量封装user原因,把它放到配置文件里解耦;一定要在src目录下,并且里面的值不能用符号或空格。只用变量=具体值 【类没发现因为没有获得连接,因为配置文件不正确,因为值后面多了空格】行级锁又称为悲观锁,在当前事务没有结束之前,被锁定的记录,精确到表中的行,其他事务是无法进行修改的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wXAUWP54-1604303154973)(JDBC/image-2027233058626.png)]

batch批处理注意事项,数据量特别大的时候,应该用statement,因为预编译存储数量有限,容易产生异常

如果觉得《数据库连接之jdbc连接池》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。