一、概述
1、什么是JDBC
JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统(DBMS)、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,使用这个类库可以以一种标准的方法、方便地访问数据库资源JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
2、JDBC API
JDBC API是一系列的接口,它统一和规范了应用程序与数据库的连接、执行SQL语句,并到得到返回结果等各类操作。声明在java.sql与javax.sql包中
3、环境准备:引入JDBC驱动程序
1)驱动程序由数据库提供商提供下载。 MySQL的驱动下载地址:http://dev.mysql.com/downloads/
2)在Java Project项目应用中添加数据库驱动jar:把jar拷贝到项目中目录中lib
3)添加到项目的类路径下在驱动jar上右键-->Build Path-->Add to Build Path
二、JDBC详细步骤
1、加载并注册驱动:
1)加载驱动,把驱动类加载到内存
注册驱动,把驱动类的对象交给DriverManager管理,用于后面创建连接等使用。
2)调用Class类的静态方法forName(),向其传递要加载的JDBC驱动的类名
//通过反射,加载与注册驱动类,解耦合(不直接依赖)
Class.forName("com.mysql.jdbc.Driver");
2、获取数据库连接:DriverManager.getConnection()
1) 可以通过 DriverManager 类建立到数据库的连接Connection,DriverManager试图从已注册的JDBC驱动程序集中选择一个适当的驱动程序。
public static Connection getConnection(String url)
public static Connection getConnection(String url,String user, String password)
public static Connection getConnection(String url,Properties info)其中Properties info通常至少应该包括 "user" 和 "password" 属性
2)JDBC URL用于标识一个被注册的驱动程序,驱动程序管理器通过这个URL选择正确的驱动程序,从而建立到数据库的连接。JDBC URL的标准由三部分组成,各部分间用冒号分隔。
jdbc:<子协议>:<子名称>
① 协议:JDBC URL中的协议总是jdbc
② 子协议:子协议用于标识一个数据库驱动程序
③ 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息
3)常用数据库URL地址的写法:
Oracle:jdbc:oracle:thin:@localhost:1521:库名
SqlServer:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=库名
MySql:jdbc:mysql://localhost:3306/库名
4)Connection()对象的常用方法:
方法 | 描述 |
createStatement() | 创建向数据库发送sql的statement对象 |
prepareStatement(sql) | 创建向数据库发送预编译sql的PrepareSatement对象 |
prepareCall(sql) | 创建执行存储过程的callableStatement对象 |
setAutoCommit(boolean autoCommit) | 设置事务是否自动提交 |
commit() | 在连接上提交事务 |
rollback() | 在此连接上回滚事务 |
3、执行增删改查:
1)PreparedStatement vs Statement
① 代码的可读性和可维护性. Statement的sql拼接是个难题。
② PreparedStatement 可以防止SQL注入
③ PreparedStatement 可以处理Blob类型的数据
④ PreparedStatement 能最大可能提高性能:(Oracle和PostgreSQL8是这样,但是对于MySQL不一定比Statement高)
2)PreparedStatement概述:可以通过调用Connection对象的preparedStatement(String sql)方法获取PreparedStatement对象
① PreparedStatement接口是Statement的子接口,它表示一条预编译过的SQL语句
② PreparedStatement对象所代表的SQL语句中的参数用问号(?)来表示,调用PreparedStatement对象的setXX()方法来设置这些参数. setXX()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从 1 开始),第
二个SQL语句中的参数的值。若不清楚数据的类型,则直接使用setObject()方法
setXX(占位符索引,占位符的值):设置对应索引的占位符的值,类型为XX类型
setObject(占位符索引,占位符的值):设置对应索引的占位符的值,类型为Object类型
1 @Test 2 public void add() throws Exception { 3 Scanner input = new Scanner(System.in); 4 System.out.println("请输入用户名:"); 5 String name = input.nextLine(); 6 7 System.out.println("请输入密码:"); 8 String gender = input.nextLine(); 9 10 //1、加载并注册驱动 11 Class.forName("com.mysql.jdbc.Driver"); 12 13 //2、建立数据库连接 14 String url = "jdbc:mysql://localhost:3306/girls"; 15 String user = "root"; 16 String password = ""; 17 Connection conn = DriverManager.getConnection(url, user, password); 18 19 //3、编写带?的SQL 20 String sql = "INSERT INTO admin VALUES(null,?,?)"; 21 22 //4、实例化PreparedStatement,对带?的sql进行预编译 23 PreparedStatement Statement = conn.prepareStatement(sql); 24 25 //5、把?用具体的值进行代替 26 Statement.setString(1, name); 27 Statement.setObject(2, gender); 28 29 //6、执行sql 30 int len = Statement.executeUpdate(); 31 System.out.println(len>0?"添加成功":"添加失败"); 32 33 //7、释放资源 34 Statement.close(); 35 conn.close(); 36 input.close(); 37 }
③ Statement对象常用方法:
方法 | 含义 |
executeQuery(String sql) | 用于向数据发送查询语句 |
executeUpdate(String sql) | 用于向数据库发送insert、update或delete语句 |
execute(String sql) | 用于向数据库发送任意sql语句 |
addBatch(String sql) | 把多条sql语句放到一个批处理中 |
executeBatch() | 向数据库发送一批sql语句执行 |
④ int executeUpdate():执行更新,包括增、删、改,返回受影响的行数
⑤ ResultSet executeQuery():执行查询,并返回该查询生成的ResultSet对象。
ResultSet对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet接口由数据库厂商实现;ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next()方法,可以使
游标指向具体的数据行,进行调用方法获取该行的数据。
A、获取行:ResultSet提供了对结果集进行滚动的方法:
next():移动到下一行
Previous():移动到前一行
absolute(int row):移动到指定行
beforeFirst():移动resultSet的最前面。
afterLast() :移动到resultSet的最后面。
B、获取值:ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:
获取任意类型的数据:
getObject(int index):通过索引
getObject(string columnName):通过列名,若sql语句中使用了AS关键字重命名列名,则使用重命名后的列名
获取指定类型的数据,如获取字符串类型的数据:
getString(int index)
getString(String columnName)
1 @Test 2 public void select() throws Exception { 3 4 Scanner input = new Scanner(System.in); 5 System.out.println("请输入姓名:"); 6 String name = input.nextLine(); 7 8 //1、加载并注册驱动 9 Class.forName("com.mysql.jdbc.Driver"); 10 11 //2、建立数据库连接 12 String url = "jdbc:mysql://localhost:3306/girls"; 13 String user = "root"; 14 String password = ""; 15 Connection conn = DriverManager.getConnection(url, user, password); 16 17 //3、编写带?的sql 18 String sql = "SELECT id,username,password FROM admin WHERE username = ?"; 19 20 //4、把带?的sql语句进行预编译 21 PreparedStatement statement = conn.prepareStatement(sql); 22 23 //5、把?用具体的变量的赋值 24 statement.setString(1, name); 25 26 //6、执行查询sql 27 ResultSet set = statement.executeQuery(); 28 while (set.next()) { 29 30 int id = set.getInt("id"); 31 String username = set.getString("username"); 32 Object pwd = set.getObject("password"); 33 34 System.out.println(id + " " + username + " " + pwd); 35 } 36 37 // 6、释放资源 38 set.close(); 39 statement.close(); 40 conn.close(); 41 input.close(); 42 }
4、释放资源:ResultSet.close()、statement.close()、connection.close()
JDBC程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。
注意:为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
三、封装JDBCUtils
1、封装类
1 public class JDBCUtils { 2 3 static String user; 4 static String password; 5 static String url; 6 static String driver; 7 8 //代码块 9 static{ 10 try { 11 //读取配置文件 12 Properties info = new Properties(); 13 info.load(new FileInputStream("src\jdbc.properties")); 14 user = info.getProperty("user"); 15 password = info.getProperty("password"); 16 url = info.getProperty("url"); 17 driver = info.getProperty("driver"); 18 //1.注册驱动 19 Class.forName(driver); 20 } catch (Exception e) { 21 //将编译异常转换为运行异常 22 throw new RuntimeException(e); 23 } 24 } 25 /** 26 * 功能:获取可用的连接对象 27 * @return 连接 28 * @throws Exception 29 */ 30 public static Connection getConnection(){ 31 32 try { 33 return DriverManager.getConnection(url, user, password); 34 } catch (Exception e) { 35 throw new RuntimeException(e); 36 } 37 } 38 /** 39 * 功能:释放资源 40 * @param set 41 * @param statement 42 * @param connection 43 * @throws Exception 44 */ 45 public static void close(ResultSet set,Statement statement,Connection connection){ 46 try { 47 if (set!=null) { 48 set.close(); 49 } 50 if (statement!=null) { 51 statement.close(); 52 } 53 if (connection!=null) { 54 connection.close(); 55 } 56 } catch (SQLException e) { 57 throw new RuntimeException(e); 58 } 59 } 60 }
2、示例
1 public class TestPreparedStatementByUtils { 2 3 @Test 4 public void testUpdate() { 5 6 Scanner input = new Scanner(System.in); 7 8 System.out.println("请输入待修改的编号:"); 9 int id = input.nextInt(); 10 11 System.out.println("请输入新用户名:"); 12 String name = input.next(); 13 14 //----------------------连接数据库的步骤---------------- 15 Connection connection = null; 16 PreparedStatement statement = null; 17 try { 18 //1.获取连接 19 connection = JDBCUtils.getConnection(); 20 21 //2.执行修改 22 String sql = "update admin set username=? where id=?"; 23 statement = connection.prepareStatement(sql); 24 statement.setString(1, name); 25 statement.setInt(2, id); 26 int update = statement.executeUpdate(); 27 System.out.println(update>0?"修改成功!":"修改失败!"); 28 } catch (SQLException e) { 29 e.printStackTrace(); 30 31 }finally{ 32 33 //3.关闭连接 34 JDBCUtils.close(null, statement, connection); 35 } 36 } 37 38 }
四、事务
1、JDBC程序中当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
2、JDBC程序中为了让多个SQL语句作为一个事务执行:(重点)
1)调用Connection对象的setAutoCommit(false); 以取消自动提交事务
2)在所有的SQL语句都成功执行后,调用commit(); 方法提交事务
3)在其中某个操作失败或出现异常时,调用rollback(); 方法回滚事务
4)若此时Connection没有被关闭, 则需要恢复其自动提交状态setAutoCommit(true);
注意:要求开启事务的连接对象和获取命令的连接对象必须是同一个!否则事务无效。如果多个操作,每个操作使用的是自己单独的连接,则无法保证事务。即同一个事务的多个操作必须在同一个连接下
3、使用步骤:
1)开启新事务
取消隐式事务自动提交的功能:setAutoCommit(false);
2)编写组成事务的一组sql语句
3)结束事务
commit();提交
rollback();回滚
4、实例
1 @Test 2 public void testTransaction(){ 3 4 Connection connection = null; 5 PreparedStatement statement = null; 6 7 try { 8 //1.获取连接 9 connection = JDBCUtils.getConnection(); 10 11 //①事务的使用步骤1:开启事务 12 connection.setAutoCommit(false); 13 14 //②事务的使用步骤2:编写sql语句,并且执行 15 statement = connection.prepareStatement("update admin set password = ? where id=?"); 16 17 //操作1:张三丰的钱-5000 18 statement.setInt(2, 1); 19 statement.setString(1, "888"); 20 statement.executeUpdate(); 21 22 //模拟异常 23 int i = 1/0; 24 25 //操作2:张三丰的钱-5000 26 statement.setInt(2, 50053); 27 statement.setString(1, "111"); 28 statement.executeUpdate(); 29 30 //③事务的使用步骤3:结束事务 31 connection.commit(); 32 33 } catch (SQLException e) { 34 try { 35 //回滚事务 36 connection.rollback(); 37 } catch (SQLException e1) { 38 e1.printStackTrace(); 39 } 40 }finally{ 41 42 JDBCUtils.close(null, statement, connection); 43 } 44 45 }
五、批处理
1、需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
2、JDBC的批量处理语句包括下面两个方法:
addBatch():添加需要批量处理的SQL语句或参数
executeBatch():执行批量处理语句;
clearBatch():清空批处理包的语句
4、注意:
1)JDBC连接MySQL时,如果要使用批处理功能,请再url中加参数?rewriteBatchedStatements=true。url=jdbc:mysql://localhost:3306/girls?rewriteBatchedStatements=true
2)PreparedStatement作批处理插入时使用values(使用value没有效果)
3)批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高
1 //没有使用批处理:耗时长 2 @Test 3 public void testNoBatch() throws SQLException{ 4 5 //1.获取连接 6 Connection connection = JDBCUtils.getConnection(); 7 8 //2.执行批量插入 9 PreparedStatement statement = connection.prepareStatement("insert into admin values(null,?,?)"); 10 11 for(int i=1;i<=50000;i++){ 12 statement.setString(1,"john"+i); 13 statement.setString(2, "0000"); 14 statement.executeUpdate();//执行 15 } 16 //3.释放资源 17 JDBCUtils.close(null, statement, connection); 18 } 19 20 //使用批处理 21 @Test 22 public void testBatch() throws SQLException{ 23 24 //1.获取连接 25 Connection connection = JDBCUtils.getConnection(); 26 27 //2.执行批量插入 28 PreparedStatement statement = connection.prepareStatement("insert into admin values(null,?,?)"); 29 30 for(int i=1;i<=50000;i++){ 31 statement.setString(1,"john"+i); 32 statement.setString(2, "0000"); 33 34 statement.addBatch();//添加sql语句到批处理包中 35 if(i%1000==0){ 36 statement.executeBatch();//执行批处理包中的sql语句 37 statement.clearBatch();//清空批处理包中的sql语句 38 } 39 } 40 41 //3.释放资源 42 JDBCUtils.close(null, statement, connection); 43 }