1.为什么使用JDBC
-
现在程序中的数据状态:瞬时的,将来程序中的数据必须是:持久化的
-
所以要把程序中的数据放在数据库中,在java程序中,如果要连接访问数据库,就需要JDBC
-
选择项目要用的数据库
-
Oracle MySQL
-
-
在使用数据库这方面,java是老大,它制定程序使用数据库的规范(接口),各个数据库厂商按照java语言的要求来提供相应的程序供开发人员使用
-
JDBC(java database connectivity),java数据库连接
-
sun公司制定的java应用程序操作关系型数据库的规范(接口),供各个数据库厂商遵循,以便它们提供自己的数据库驱动(实现类,操作自己的数据库)。
-
2.JDBC连接数据库的步骤
public static void main(String[] args) throws Exception {
//1.导入驱动jar包
//2.加载数据库驱动类
//Class.forName("com.mysql.cj.jdbc.Driver");
//3.连接数据库,获取数据库连接对象
//数据库使用的时区和本地时区有区别,UTC是统一世界标准时间
Connection connection = DriverManager
.getConnection("jdbc:mysql://127.0.0.1:3306/mwb?serverTimezone=UTC","root","123456");
System.out.println(connection + "数据库连接成功");
//4.操作数据库
//4.1查询数据库
//定义查询SQL,注意select后面不能出现*
String sql = "select empno eno, ename, sex, hiredate from emp";
//5.获取执行sql的Statement对象
Statement statement = connection.createStatement();
//6.执行SQL,获取查询结果集
ResultSet resultSet = statement.executeQuery(sql);
//7.遍历结果集
System.out.println("员工编号\t员工姓名\t性别\t入职日期");
while(resultSet.next()) {//next():判断是否还有下一条记录,有的话就指向这条数据
//循环一次,代表获取一条记录
//int---getInt() varchar---getString() double---getDouble()
System.out.println(resultSet.getInt("eno") + "\t"
+ resultSet.getString("ename") + "\t"
+ resultSet.getString("sex") + "\t"
+ resultSet.getString("hiredate"));
}
//8.关闭资源 connection、statement、resultset //注意异常处理
resultSet.close();
statement.close();
connection.close();
}
-
导入驱动jar包:
-
在项目下创建lib文件夹,将驱动jar包复制到该文件夹下
-
右键lib文件夹,选择add as Library
-
-
加载驱动程序
-
通过Class.forName("类名")加载到JVM中,驱动被加载成功后,就自动注册到DriverManager里去里
-
-
获取数据库连接对象
-
Connection conn = DriverManager.getConnection(url,user,password)
-
url就是连接数据库的url(网址,统一资源定位符)
-
连接mysql数据库的url为:jdbc:mysql://127.0.0.1:3306/mwb?serverTimezone=UTC
-
组成
-
协议:jdbc
-
子协议:mysql
-
数据库所在服务器的IP地址:如果是本机是localhost或127.0.0.1
-
端口号:3306
-
数据库名称:mwb
-
统一世界标准时间:serverTimezone=UTC
-
-
-
-
定义sql语句
-
涉及字符串的拼接
-
StringBuffer append()
-
StringBuffer转换为String toString()
-
-
-
获取一个执行sql的对象Statement,它执行的是静态的sql
-
获取Statement对象:Statement statement = conn.createStatement();
-
执行sql时,常用的方法有以下三种
-
execute():可以执行所有的sql语句,但是因为它的返回值是boolean类型,所以很少使用
-
executeQuery():执行DQL(select)语句,它的返回值是结果集ResultSet
-
executeUpdate():这个方法是用来更新数据的,一般用它来执行DML(insert、update、delete)语句,返回值类型为int,代表你的sql语句作用了几条记录,通过这个值可以判断sql语句是否执行成功,大于0则执行成功,否则执行失败
-
-
-
获取结果集
-
ResultSet rs = statement.executeQuery(sql);
-
遍历结果集,通过rs的next()方法,注意:此方法包含判断结果集中是否还有记录以及向下移动记录
-
获取具体的字段值时,需要根据数据库表中字段的数据类型来选择相应的方法
-
int(10)----getInt("字段名"),这里的字段名时select后的字段,不是数据库表中的字段
-
varchar(100)----getString("字段名")
-
-
关闭资源
-
所有的资源在使用完后必须释放,也就是通过close()方法关闭
-
Connection Statement ResultSet的对象
-
-
注意处理异常
3.JDBC API
-
由sun公司开发的,供程序员调用的接口和类
-
数据库驱动程序:由各个数据库厂商根据JDBC规范开发的jar包
-
DriverManager类:管理各个数据库驱动程序的类
-
注册驱动
-
获取数据库连接
-
-
Connection接口:负责连接数据库并承担数据传输任务的接口,每连接到一个数据库就会获得一个连接对象
-
获取执行SQL的statement对象
-
管理事务
-
开启事务、提交事务、回滚事务
-
-
-
Statement接口:由Connection产生,用来执行具体的静态的sql语句
-
PreparedStatement接口:用来执行动态的或称为预编译的sql语句
-
ResultSet接口:查询结果集,负责保存执行查询语句后所产生的查询结果(executeQuery的返回值类型)
4.资源的释放
-
程序的执行不论成功还是失败,都应对资源进行释放,因为资源是占用内存的,所以应该将资源的释放放在finally中,异常的处理应该使用try-catch,不应该抛出
public static void main(String[] args) { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Connection conn = null; Statement statement = null; try { conn = DriverManager .getConnection("jdbc:mysql://127.0.0.1:3306/mwb?serverTimezone=UTC","root","123456"); String sql = "update emp set ename='貂蝉', sex='女' where empno=4"; statement = conn.createStatement(); int num =statement.executeUpdate(sql); if (num > 0) { System.out.println("修改成功"); } else { System.out.println("修改失败"); } } catch (SQLException e) { e.printStackTrace(); } finally { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }
5.PreparedStatement
public static void main(String[] args) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DriverManager
.getConnection("jdbc:mysql://127.0.0.1:3306/mwb?serverTimezone=UTC","root","123456");
//使用?做占位符,有几个值写几个?
String sql = "insert into emp values(null, ?, ?, ?)";
//创建PreparedStatement对象,PreparedStatement继承了Statement,同时预编译sql
ps = conn.prepareStatement(sql);
//设置占位符内容,有几个问号,就需要几个值
ps.setString(1, "赵云");
ps.setString(2, "男");
ps.setString(3, "2022-04-09");
//执行sql
int num = ps.executeUpdate();
if (num > 0) {
System.out.println("新增成功");
} else {
System.out.println("新增失败");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (ps != null) {
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
assert conn != null;
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
-
PreparedStatement接口继承了Statement接口,项目中一般使用PreparedStatement, 用于执行预编译的动态的SQL,这个对象执行的SQL语句中,通过?占位符来设置数据或字段
-
优点: 1.可以更加灵活方便的设置参数,使用了?占位符 2.提高了代码的可读性,可维护性和复用性 3.提高了sql语句执行的性能,有一个预编译的过程 4.提高了代码的安全性,有效防止sql注入,用?占位符,是将输入作为一个整体
6.JDBC对事务的支持
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mwb?serverTimezone=UTC","root","123456");
//关闭自动提交,开启事务
conn.setAutoCommit(false);
//执行多条新增操作
String sql = "insert into emp (ename, sex, hiredate) values(?,?,?)";
//创建PreparedStatement对象,并预编译SQL
ps = conn.prepareStatement(sql);
//设置占位符内容
//插入第一个员工
ps.setString(1,"小乔");
ps.setString(2,"女");
ps.setString(3,"2022-03-07");
//执行sql
ps.executeUpdate();
//插入第二个员工
ps.setString(1,"周瑜");
ps.setString(2,"男");
ps.setString(3,"2022-02-07");
ps.executeUpdate();
///提交事务
conn.commit();
} catch (SQLException e) {
try {
if (conn != null) {
conn.rollback();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
try {
if (ps != null) {
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
-
数据库事务:数据库中的最小执行单元,通常包含一条或多条sql,这些sql要么全部执行成功,如果有一条执行失败,则全部回滚。
-
JDBC连接提供了事务支持,由Connection提供
-
默认情况下,Connection开启自动提交,即关闭事务,执行完一条sql语句后就直接更新到数据库
-
在执行sql语句之前调用Connection的setAutoCommit(false)关闭自动提交
-
关闭自动提交,开启事务
-
connection.setAutoCommit(false);
-
-
一般项目中涉及到批量操作(增删改)的时候,我们才会将它设置为false,然后通过Connection的commit()来提交,单独的增删改,不需要设置
-
提交事务
connection.commit();
-
-
如果任意一条sql语句执行失败,则需要使用Connection的rollback()来回滚事务,保证操作的原子性
-
回滚事务:
connection.rollback();
-
-
-
注意:实际上,当Connection遇到一个未处理的SQLException时,系统会非正常退出,事务也会自动回滚,但是如果程序捕获到了该异常,则需要在异常处理块中显式的回滚事务
7.JDBC批处理
-
将多条sql语句一次性发送到服务器,而不是多条sql发送多次
-
除事务的支持外,jdbc还提供了批量更新的功能,即多条sql被作为一批操作被同时收集并同时执行
-
JDBC批量更新-->Statement
try { conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mwb?serverTimezone=UTC","root","123456"); statement = conn.createStatement(); //执行多条删除操作 String sql1 = "delete from emp where empno = 1"; //通过addBatch()方法添加多条sql statement.addBatch(sql1); String sql2 = "delete from emp where empno = 2"; statement.addBatch(sql2); String sql3 = "delete from emp where empno = 3"; statement.addBatch(sql3); //批量执行 statement.executeBatch(); }
-
JDBC批量更新-->PreparedStatement
try { conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mwb?serverTimezone=UTC","root","123456"); String sql = "update emp set hiredate = ? where empno = ?"; ps = conn.prepareStatement(sql); //第一个员工 ps.setString(1,"2021-09-08"); ps.setInt(2,4); //添加sql ps.addBatch(); ps.setString(1,"2020-02-02"); ps.setInt(2,5); ps.addBatch(); //统一执行 ps.executeBatch(); }