下面我们通过几个JDBC案例来理解JDBC在java中的应用
在开始学习案例之前,我们应该先对JDBC的使用流程和使用规范有一个大致了解
1.基本应用
JDBC使用规则:
JDBC调用流程:
1.将MySQL服务器厂商提供的Driver接口实现类注册到JVM
2.通过JDBC规范中DriverManager在Java工程与MySQL服务器之间建立一个[连接通道]
3.通过MySQL服务器厂商提供Connection接口实现类建立一个交通工具[PrepareStatement]
4.通过交通工具[PrepareStatement]将SQL命令从Java工程推送到MySQL服务器上执行 并带回执行结果
5.销毁本次交易过程中的所有资源对象
JDBC规范下接口介绍:
1.位置:存在于JDK_1.8.jar下java.sql包
2.分类:(1)java.sql.DriverManager类:这个类存在于JDK_1.8.负责将数据库厂商提供的Driver接口实行注册,负责在java和MySQL之间建立一个连接通道
(2)java.sql.Connection接口:
负责管理java工程与数据库服务器之间的连接通道
(3)java.sql.PreparedStatement接口:
负责管理在 连接通道 上进行往返运输的 交通工具
(4)java.sql.ResultSet接口:
负责管理数据库服务器所返回的临时表
了解了这些后我们便可以通过下面几个案例加强对JDBC使用流程的理解
案例一:通过JDBC向MySQL服务器推送添加数据命令
public class 推送添加命令 {
public static void main(String[] args) throws SQLException {
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);//这句可以省略
//1.将MySQL服务器提供的jar包中的driver接口实现类注册到JVM
String url = "jdbc:mysql://localhost:3306/name";
//ucr的格式:"jdbc:mysql//服务器所在计算机IP地址:服务端口号/数据库"
Connection connection = DriverManager.getConnection(url, "root", "233");//这里的root和233是指数据库的账户及密码
//2.通过DriverManager创建一个java和MySQL之间的通道并交给connection管理
PreparedStatement ps = connection.prepareStatement("");//3.在通道上建一个交通工具用于运输命令并交给ps管理
//注意这里应该是要放入SQL语句的,只不过我们只是定义,所以可以令它为空,相当于一辆"空车"
int result = ps.executeUpdate("insert into dept (deptno,dname,loc) values(88,'bookstore','CN')");
//4.通过交通工具ps将SQL命令推送到MySQL服务器上执行并带回处理结果
//返回的是添加数据的数量,如果添加的数据已经存在会导致异常
//5.销毁相关资源
if(ps!=null)//在销毁前应先确认ps是否任然存在,以防止程序出现异常导致ps已经销毁
{
ps.close();
}
if(connection!=null){
connection.close();
}
System.out.println("本次交易中共添加了"+result+"个数据");
}
}
案例二:通过JDBC向MySQL服务器推送更新数据命令
public class 推送更新命令 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");//第二种将Driver实现类注册到JVM的方式
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/name", "root", "233");
PreparedStatement ps = connection.prepareStatement("");
int result = ps.executeUpdate("update dept set loc = '贵州' where deptno <>90 ");
if(ps!=null){
ps.close();
}
if(connection!=null){
connection.close();
}
System.out.println("本次交易更新了"+result+"条数据");
}
}
案例三:通过JDBC向MySQL服务器推送查询命令
public class 推送查询命令 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
String sql ="select dname from dept where dname like '_c%'";//书写查询语句
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/name", "root", "cjysql233");
PreparedStatement ps = connection.prepareStatement("");
ResultSet rs = ps.executeQuery(sql);
//使用while遍历ResultSet得到查询结果
while (rs.next()){
String dname = rs.getString("dname");
System.out.println(dname);
}
//注意ResultSet建立在PrepareStatement之上,所以应该先做完对ResultSet的操作再关闭Statement
if(rs!=null){
rs.close();
}
if(ps!=null){
ps.close();
}
if(connection!=null){
connection.close();
}
}
}
通过以上三个案例,我们大概就了解了JDBC在java中的使用流程,但我们也会发现这三个简单案例存在着许多问题,最突出的有
1.SQL语句书写繁琐,容易出错
2.executeUpdate()每次执行,都是要将java->MySQL->java进行一圈,造成了时间和空间的大量浪费
3.没有运用到MySQL中的事务功能,实际运用中大多数的操作应该都是由事务来处理的
那么我们如何解决这些问题呢
可以通过接下来的两个案例来体会一下
2.事务管理与批处理
案例四:事务管理
/*
规则:
在一个需求中,只要有任一个SQL命令无法执行,此时应将需求中所SQL命令都判定为执行失效
*/
public class 事务管理 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/name","root","233");
//通过连接通道推送 "start transaction"命令,开启一个事务
connection.setAutoCommit(false);
//如果连接处于自动提交模式下,则其所有的SQL语句将作为单个事务运行并提交。否则,其SQL语句将作为事务组,直到调用Commit方法或rollback方法为止。默认情况下,新连接处于自动提交模式。
//setAutoCommit传入得值为true时,将启用自动提交模式,此时SQL语句有MySQL服务器进行管理,传入false时,关闭自动提交,开启一个事务,此时SQL语句由事务进行管理
PreparedStatement ps = connection.prepareStatement("");
//注意:只有当表的存储引擎为innodb时才会有备份,事务的回滚才能使用,可以使用 alter table 表名 engine = innodb语句来将表的存储引擎设置为innodb,通过show create table 表名 来查看当前表的存储引擎
try{//通过try..catch..来捕获异常确保当任一SQL语句出现问题时,能够对本次事务进行回滚,将本次操作中所有文件的备份覆盖表文件,取消本次操作
ps.executeUpdate("delete from emp where deptno = 20");
ps.executeUpdate("delete from dept where deptno= 20");
//如果能走到这里则证明推送的SQL语句都能正常运行,故而可以提交数据,关闭事务,通知MySQL服务器将备份文件删除
connection.commit();//向MySQL服务器推送 "commit;"关闭事务
}catch (SQLException sqlException){
connection.rollback();//向MySQL服务器推送 "rollback;"进行回滚
}finally {
//销毁
if (ps != null) {
ps.close();
}
if (connection != null) {
connection.close();
}
}
}
}
案例五:批处理尝试
public class 批处理尝试 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//预编译形式SQL语句
String sql ="insert into dept (deptNo,dname,loc) values (?,?,?)";
//"?"是占位符,一个问号代表一个值
//预编译SQL相当于一个模具,在后续开发时,只需要将数据填充到占位符,就可以得到一个全新的SQL
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/name", "root", "cjysql233");
//我们建立交通工具时,需要将预编译SQL语句注册到PrepareStatement中
PreparedStatement ps = connection.prepareStatement(sql);
for(int i = 0;i<=50;i++){
//通过向预编译SQL语句中填充数据来生成新的SQL命令
ps.setInt(1,i);// 1 指ps所装载的预编译SQL语句中的第一个占位符"?",后面的 i 就是要填入占位符的数据
ps.setString(2,"dept"+i);
ps.setString(3,"CN");
//为了实现SQL语句能成批进行运送处理,而不是一次一次的单独完成往返任务,我们需要像填充子弹一样将已经写好的SQL语句填入"弹夹",等待一起发射
ps.addBatch();//将SQL语句加入弹夹
}
int[] ints = ps.executeBatch();//[一次性]将所有SQL语句推送到MySQL服务器,即"扣动扳机",Batch其实是一个list
//executeBatch()返回一个整形数组,数组内的值为其"弹夹"内的每一条语句所影响的行数,其中如果返回-2的值,表示命令为处理成功,但受影响的行数为未知,返回-3表示该语句无法执行,驱动程序将跳过它继续向下处理
//如果批量更新中的命令之一无法正确执行,此方法引发BatchUpdateException,JDBC driver可能会也可能不会继续处理剩余的命令。但是driver的行为是与特定的DBMS绑定的,要么总是继续处理命令,要么从不继续处理命令。如果驱动程序继续处理,方法将返回 EXECUTE_FAILED(-3)。
for (int i = 0; i < ints.length; i++) {
System.out.println("语句"+i+"执行成功,进行了"+ints[i]+"个操作");
}
if(ps!=null){
ps.close();
}
if (connection != null) {
connection.close();
}
}
}
这下就可以解决之前出现的那些问题啦
虽然这样也能进行对数据库的增删改查操作,但实际运用中我们更多的是采用封装的方式,因此我们也要知道JDBC的工具类是如何封装的,可以看看下面这个文章了解一下
这些案例主要来源于动力节点老杨的课程,感兴趣的同学可以看看B站动力节点java web
以上是我自己整理的笔记和理解,如果有错误欢迎大家评论区交流指正,如果有什么好的课程也希望大家能分享一下呀