JDBC
目录
5.PerparedStatement(sql预处理命令对象)
6.Statement对象与PerparedStatement对象之间的区别及联系
一.idea下创建JDBC项目
1.下载所需JDBC驱动
2.连接数据库
请参考以下博客在idea上连接数据库:https://blog.csdn.net/lgl782519197/article/details/108980141
3.创建JDBC项目
请参考以下博客在idea上创建JDBC项目:最新Intellij Idea2020.01使用JDBC连接数据库_imok的博客-CSDN博客_idea2020连接数据库
建议读者在创建JDBC项目时,依照笔者顺序依次浏览博客创建项目(说实话在idea上创建一个JDBC项目着实有亿点点小难)
二.JDBC常用类及常用方法介绍
首先在详解JDBC常用类及常用方法之前,笔者这里简单说明数据库连接过程:见下图
写在前面: 在使用JDBC对象之前需要使用Class类中的forName(String className)方法
1.DrivaerManger(驱动管理对象)
(1)对象功能:DriverManger类负责驱动程序管理,而数据库驱动则是为了应用程序服务的,所以DriverManger的任务就是提供数据库连接的获取
(2)常用方法介绍:
Connection getConnection(String url,String username,String password) | 通过数据库的URL(url),用户名(username),密码(password)建立跟数据库之间的连接并返回Connection对象 |
2.Connection(数据库连接对象)
(1)对象功能:获取执行SQL的对象
(2)常用方法介绍:
Statement createStatement() | 创建向数据库发送SQL指令的对象,返回Statement对象 |
Statement preparedStatement(String sql) | 创建向数据库发送SQL指令的对象,返回PreparedStatement对象 |
close() | 关闭Connection对象 |
3.Statement(sql执行对象)
(1)对象功能:执行sql语句
(2)常用方法介绍:
Boolean execute(String sql) | 执行sql语句,返回是否有结果集的Boolean值 |
ResultSet executeUpdate() | 执行sql语句SELECT,返回ResultSet结果集 |
Int executeQuery() | 执行sql语句INSERT,DELETE,UPDATE,返回修改的行数 |
close() | 关闭Statement对象 |
4.ResultSet(结果集接口)
(1)接口功能:操作sql语句执行结果
(2)常用方法介绍:
Boolean next() | 将光标移动到下一条记录,如果返回值为false,则已到文件尾 |
Int getInt(int columnIndex) | 根据columnIndex返回整型内容 |
String getString(int columnindex) | 根据columnIndex返回字符型内容 |
close() | 关闭ResultSet对象 |
5.PerparedStatement(sql预处理命令对象)
(1)对象功能:预编译SQl语句,并执行SQl语句
(2)常用方法介绍:
Boolean execute(String sql) | 执行sql语句,返回是否有结果集的Boolean值 |
ResultSet executeUpdate() | 执行sql语句SELECT,返回ResultSet结果集 |
Int executeQuery() | 执行sql语句INSERT,DELETE,UPDATE,返回修改的行数 |
setString()/setInt()/setdouble()/setBoolean() | 给SQL语句中未知变量赋值 |
close() | 关闭PerparedStatement对象 |
6.Statement对象与PerparedStatement对象之间的区别及联系
(1)联系:
PerparedStatement对象继承自Statement对象,用PerparedStatement对象生成的实例已经包含了编译后的SQL语句,执行效率高于Statement对象
(2)区别:
<1>编译层面
Statement对象每次执行执行SQl语句,都要在相应的数据库编译一次
PerparedStatement对象事先对SQL语句进行预编译,再填充参数,执行时无需编译直接解析运行
<2>执行层面
对于数据量较小的SQL语句进行操作时,Statement对象执行效率要高于PerparedStatement对象
而对于数据量较大的SQl语句进行操作时,由于PerparedStatement对像预编译一次SQL语句,便可以直接执行;而Statement需要每次编译再执行,所以PerparedStatement对象执行效率高于Statement对象
7.代码演示JDBC
笔者先在navicat上创建了一个表单文档,用来储存银行中的用户信息(包括存款银行(bankname),用户姓名(username),账户密码(userpassword),用户性别(sex),用户年龄(age),账户余额(money)以及用户移动手机号码(mobilephone)七个信息)
代码有三部分组成:test.java,mange.java,jdbcExample.java
text.java实现用户信息的封装(控制层)
mange.java实现数据库中用户数据的增,删,改,查操作(模型层)
jdbcExample.java实现数据操作结果的呈现以及操作的指令的传递(视图层)
navicat建立表单操作代码如下:
create table bankinformation( sno int(6), bankname varchar(20), username varchar(20), userpassword varchar(15), sex varchar(10), age int(5), money int(10), mobilephone int(20) )
效果展示:
text,java代码如下:
public class test { private String bankname = null;//设置用户银行名 private String username = null;//设置用户名 private String userpassword = null;//设置用户密码 private String sex = null;//设置用户性别 private int age = 0;//设置用户年龄 private int money = 0;//设置用户账户余额 private String usermobilephone = null;//设置用户手机号码 //封装用户数据 public void setBankname(String bankname) { this.bankname = bankname; } public String getBankname() { return this.bankname; } public void setUsername(String username) { this.username = username; } public String getUsername() { return this.username; } public void setUserpassword(String userpassword) { this.userpassword = userpassword; } public String getUserpassword() { return this.userpassword; } public void setUsersex(String sex) { this.sex = sex; } public String getUsersex() { return this.sex; } public void setUserage(int age) { this.age = age; } public int getUserage() { return this.age; } public void setUsermoney(int money) { this.money = money; } public int getUsermoney() { return this.money; } public void setUsermobilephone(String mobilephone) { this.usermobilephone = mobilephone; } public String getUsermobilephone() { return this.usermobilephone; } }
mange.java代码如下:
连接数据库bank_usernameinformation的URL,用户名,密码如下:
final String URL="jdbc:mysql://127.0.0.1:3306/bank_usernameinformation"; final String name="root"; final String password="aqudbkm82562935";
addUserInformation()方法:增添数据库中用户数据
public void addUserInformation() throws Exception{ System.out.println("输入想要添加的用户信息"); Scanner scanner = new Scanner(System.in); test adduser = new test(); System.out.println("请输入添加用户的银行姓名"); adduser.setBankname(scanner.next()); System.out.println("请输入添加用户的姓名"); adduser.setUsername(scanner.next()); System.out.println("请输入添加用户的密码"); adduser.setUserpassword(scanner.next()); System.out.println("请输入添加用户的性别"); adduser.setUsersex(scanner.next()); System.out.println("请输入添加用户的年龄"); adduser.setUserage(scanner.nextInt()); System.out.println("请输入添加用户的账户余额"); adduser.setUsermoney(scanner.nextInt()); System.out.println("请输入添加用户的手机号"); adduser.setUsermobilephone(scanner.next()); Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection(URL,name,password); String sql = "insert into bankInformation " + "(bankname,username,userpassword,sex,age,money,mobilephone)" + " values(?,?,?,?,?,?,?);"; PreparedStatement ps = connection.prepareStatement(sql); ps.setString(1, adduser.getBankname()); ps.setString(2, adduser.getUsername()); ps.setString(3, adduser.getUserpassword()); ps.setString(4, adduser.getUsersex()); ps.setInt(5, adduser.getUserage()); ps.setInt(6, adduser.getUsermoney()); ps.setString(7, adduser.getUsermobilephone()); ps.executeUpdate(); ps.close(); connection.close(); }
updateUserInformation()方法:更新数据库中用户信息
public void updateUserInformation() throws Exception{ Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection(URL,name,password); System.out.println("请输入要修改信息的用户名"); Scanner scanner = new Scanner(System.in); String targetusername = scanner.next(); int Number = searchUserInformation(targetusername);//Number为返回数据的数量 int number = 1;//number用来接收用户发来的数字 String update = "update bankinformation"; test updateuser = new test(); String string = null;//字符串string用于处理同一用户在不同银行存款情况 if(Number>1) {//该部分处理同一用户在不同银行存款的情况 System.out.println("请输入想要更改信息的银行名"); string = scanner.next(); } while(number!=0) { System.out.println("请按照编号输入要更改的用户信息:"); System.out.println("输入数字1更改银行"); System.out.println("输入数字2更改用户姓名"); System.out.println("输入数字3更改用户密码"); System.out.println("输入数字4更改用户性别"); System.out.println("输入数字5更改用户年龄"); System.out.println("输入数字6更改账户余额"); System.out.println("输入数字7更改用户移动手机号码"); System.out.println("输入数字0更改完毕"); number = scanner.nextInt(); if(number!=0) { switch (number) { case 1:System.out.println("请输入更改完的银行名字"); updateuser.setBankname(scanner.next()); update = update + " set bankname=?";break; case 2:System.out.println("请输入更改完的用户姓名"); updateuser.setUsername(scanner.next()); update = update + " set username=?";break; case 3:System.out.println("请输入更改完的用户密码"); updateuser.setUserpassword(scanner.next()); update = update + " set userpassword=?";break; case 4:System.out.println("请输入更改完的用户性别"); updateuser.setUsersex(scanner.next()); update = update + " set sex=?";break; case 5:System.out.println("请输入更改完的用户年龄"); updateuser.setUserage(scanner.nextInt()); update = update + " set age=?";break; case 6:System.out.println("请输入更改完的用户余额"); updateuser.setUsermoney(scanner.nextInt()); update = update + " set money=?";break; case 7:System.out.println("请输入更改玩的用户移动电话号码"); updateuser.setUsermobilephone(scanner.next()); update = update + " set mobilephone=?";break; default:break; } PreparedStatement ps = null; if(string!=null) { update = update + " where bankname=?"; ps = connection.prepareStatement(update); } else { update = update + " where username=?"; ps = connection.prepareStatement(update); } switch (number) { case 1:ps.setString(1,updateuser.getBankname());break; case 2:ps.setString(1,updateuser.getUsername());break; case 3:ps.setString(1,updateuser.getUserpassword());break; case 4:ps.setString(1,updateuser.getUsersex());break; case 5:ps.setInt(1,updateuser.getUserage());break; case 6:ps.setInt(1,updateuser.getUsermoney());break; case 7:ps.setString(1,updateuser.getUsermobilephone());break; default:break; } if(string!=null) { ps.setString(2,string); } else { ps.setString(2,targetusername); } ps.execute(); ps.close(); update = "update bankinformation"; } else break; } }
searchUserInformation()方法:查询用户信息
public int searchUserInformation(String Targetusername) throws Exception { Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection(URL,name,password); String targetusername; if(Targetusername!=null) targetusername = Targetusername; else { Scanner scanner = new Scanner(System.in); targetusername = scanner.next(); } String search = "select * from bankinformation where username=?;"; PreparedStatement ps = connection.prepareStatement(search); ps.setString(1,targetusername); ResultSet rs = ps.executeQuery(); int flag=0;//该处设置flag是为了标记是否查询到用户信息 int number=0;//记录返回数据数量 while(rs.next()) { System.out.println(rs.getString("bankname")+","+ rs.getString("username")+","+ rs.getString("userpassword")+","+ rs.getString("sex")+","+ rs.getInt("age")+","+ rs.getInt("money")+","+ rs.getString("mobilephone")); flag=1;//若查询到用户信息,将flag值置为1 number++; } if(flag==0)//判断flag的值,若为1则查询到用户信息,否则查无此人 System.out.println("查无此人"); return number; }
deleteUserInformation()方法:删除用户信息
public void deleteUserInformation() throws Exception { System.out.println("输入要删除信息的用户名"); Scanner scanner = new Scanner(System.in); String deleteusername = scanner.next(); Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection(URL,name,password); String delete = "delete from bankInformation where username=?"; PreparedStatement ps = connection.prepareStatement(delete); ps.setString(1,deleteusername); ps.execute(); ps.close(); System.out.println("删除成功"); }
jdbcExample.java代码如下:
在数据库中增添用户信息代码:
mange mange1 = new mange(); mange1.addUserInformation();
控制台运行效果如下:
navicat查询效果如下:
在数据库中查询用户信息代码:
mange mange1 = new mange(); System.out.println("请输入要查询的用户姓名"); Scanner scanner = new Scanner(System.in); String targetusername = scanner.next(); mange1.searchUserInformation(targetusername);
控制台运行效果如下:
在数据库中更改用户信息代码:
mange mange1 = new mange(); mange1.updateUserInformation();
控制台运行效果如下:
navicat查询效果如下:
在数据库中删除用户信息代码:
mange mange1 = new mange(); mange1.deleteUserInformation();
控制台运行效果如下:
navicat查询效果如下:
特殊情况处理(同一人在不同的银行中拥有存款记录):
数据库如图:
实现单一删除一条数据
控制台运行效果截图:
navicat查询效果如下:
如此便完成的数据库的增,删,改,查操作
三.JDBC事务管理
1.事务的概念
通常认为事务需要满足ACID四个特性即原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability )
(1)原子性:要求事务执行过程中任何失败都将导致对数据库所做的操作失效
(2)一致性:要求事务执行失败时,于该事务关联的所有数据都将会恢复到执行前的状态
(3)隔离性:要求事务执行过程中对数据的修改,对于其他事务来说不可见
(4)持久性:要求事务执行失败时,数据的状态都应正确
2.代码演示
对于JDBC事务的演示,笔者延续上个代码并在此基础上进行相关事务操作的增添
在原有银行账户信息数据库(bankInformation)基础上,额外新建一个表单用来表示用户收支情况(userinputoutputdatabase),要求银行中的账户余额信息能够根据获得的用户收支数据进行数据的更新
代码要求对于用户的收支记录进行计算,如果收入>支出,则在相应的银行信息中增添账户余额;否则,相应的减少账户余额(注意:账户余额最低只能为0,不允许出现负数)
navicat上表单建立并导入数据代码:
create table userinputoutputdatabase( sno int(6), username varchar(15), -- 5 个字符 sex varchar(10), inputmoney int(10), outputmoney int(10) ); insert into userinputoutputdatabase values(1,"张三","男",30000,1000);
效果如下:
bankInformation数据库如图:
test.java与mange.java代码不变,这里就不再演示
新增money.java实现用户收支数据的封装以及对用户收支信息的计算
新增operate.java实现对于用户所有收支记录的操作并对应在银行账户余额数据进行更改
money.java代码如下:
public class money { private int inputmoney; private int outputmoney; public void setInputMoney(int inputmoney) { this.inputmoney = inputmoney; } public int getInputMoney() { return this.inputmoney; } public void setOutputMoney(int outputmoney) { this.outputmoney = outputmoney; } public int getOutputMoney() { return this.outputmoney; } }
operate.java代码如下:
public class operate { final String URL="jdbc:mysql://127.0.0.1:3306/bank_usernameinformation"; final String name="root"; final String password="aqudbkm82562935"; public void calculateUserMonney(String username) throws Exception{ Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection(URL,name,password); Scanner scanner = new Scanner(System.in); //以下部分功能为计算用户所有收支记录的金额总值Money String SQL = "select inputmoney,outputmoney from userinputoutputdatabase where username=?"; PreparedStatement ps = connection.prepareStatement(SQL); ps.setString(1,username); ResultSet rs = ps.executeQuery(); money money = new money(); int inputmoney =0; int outputmoney=0; while(rs.next()) { inputmoney = inputmoney + rs.getInt("inputmoney");//处理多条收支记录 outputmoney = outputmoney + rs.getInt("outputmoney"); } money.setInputMoney(inputmoney); money.setOutputMoney(outputmoney); int Money = money.getInputMoney()-money.getOutputMoney(); ps.close(); //以下代码主要功能为对于Money进行bankInformation数据库账户余额数据的更新 mange mange1 = new mange(); int Number = mange1.searchUserInformation(username); String bank=null; String sql = "select money from bankInformation where username=?"; String Sql = "update bankinformation set money=? where username=?"; if(Number>1) { //此处代码功能为处理同一用户在不同银行存款情况,并询问用户在那个银行记录上更改 System.out.println("请选择更改记录的银行"); bank = scanner.next(); sql = sql + " and bankname=?"; Sql = Sql + " and bankname=?"; } //此处代码用于获取用户银行存款数据 PreparedStatement PS = connection.prepareStatement(sql); PS.setString(1,username); if(Number>1) PS.setString(2,bank); ResultSet RS = PS.executeQuery(); int money1 = 0; while(RS.next()) { money1 = RS.getInt("money"); } //此处代码用于更改账户余额数据 PreparedStatement ps1 = connection.prepareStatement(Sql); if(money1+Money<0) //若账户余额不足以付清支出数据,则账户余额制位0 ps.setInt(1,0); else ps1.setInt(1,money1+Money); ps1.setString(2,username); if(Number>1) ps1.setString(3,bank); ps1.execute(); ps1.close(); System.out.println("记录完毕"); }
代码运行效果截图:
(1)正常情况:
控制台运行效果:
navicat查询结果如下:
结果显示相应银行数据库中数据有更改
(2)特殊情况1:(同一用户在不同银行存款)
数据库更改为:
控制台运行效果:
navicat查询结果为:
三.JDBC连接池
1.概念
存放数据库连接的一个容器(集合)Connection
2.JDBC产生背景
对于某些与数据库连接较多的大型网站,需要一个专门用于储存连接的容器,也即连接池
3.实现连接池
(1)C3P0:需要先下载对应的jar包
下载地址:https://sourceforge.net/projects/c3p0/
(2)Druid:需要先下载对应的jar包
下载地址:https://repo1.maven.org/maven2/com/alibaba/druid/1.1.22/
笔者这里对于JDBC连接池讲解较为粗浅,详情请参考博客:https://blog.csdn.net/zjdzka/article/details/112093966