JDBC数据库连接
📅 2026/8/2 19:34:11
👁️ 阅读次数
📝 编程学习
介绍
jdbc:java数据库连接技术,通俗点说,在java代码中使用JDBC提供的方法,可以发送字符串类型的sql语句到数据库管理软件,并且获取语句执行结果,进而实现数据库CRUD操作技术
优势:只需要学习jdbc接口规定方法,即可操作所有的数据库软件,项目中期需要切换数据库,我们只需要更新第三方驱动jar包,不需要更改代码。
jdbc核心api和使用路线
1.jdk下jdbc规范接口,存储在java.sql和javax.sql包中的api
为了项目的可移植性,可维护性,sun公司最初就制定了java程序连接各种数据库的统一接口规范
2.各个数据库厂商提供的驱动jar包
涉及具体核心类和接口
DriverManger
1.将第三方数据库厂商的实现驱动jar注册到程序中
2.可以根据数据库连接信息获取connection
Connection
1.和数据库建立的连接,在连接对象上,可以多次执行数据库crud动作
2.可以获取statement preparestatement callablestatement对象
Statement PreparedStatement CallableStatement
1.具体发送sql语句到数据库管理软件的对象
2.不同的发送方式稍有不同
Result
1.面向对象的产物(抽象成数据库的查询结果表)
2.存储DQL查询数据库结果的对象
3.需要我们进行解析,获取具体的数据库数据
JDBC API使用路线
为什么使用全新8+版本mysql-jdbc驱动
支持jdk1.8版本语法变更新特性
支持全新的驱动api,增加自动时区选择和默认utf-8编码格式等配置
核心API Statement
package com.at; import com.mysql.cj.jdbc.Driver; import java.sql.*; public class Main { public static void main(String[] args) throws SQLException { DriverManager.registerDriver(new Driver()); /*获取连接 * * java程序要和数据库创建连接 * java程序,连接数据库,肯定是调用某个方法,方法也需要填入连接数据库的基本信息 * * 数据库ip地址:127.0.0.1 * 数据库端口号:3306 * 账号 * 密码 * */ /*java.sql 接口=实现类*/ Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/studb", "root", "080666"); /*创建statement*/ Statement statement = connection.createStatement(); String sql="select *from students"; ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()){ int id = resultSet.getInt("id"); String name = resultSet.getString("name"); int password = resultSet.getInt("age"); System.out.println(id+" "+name+" "+password); } resultSet.close(); statement.close(); connection.close(); } }package com.at; import com.mysql.cj.jdbc.Driver; import javax.sql.DataSource; import java.sql.*; import java.util.Properties; import java.util.Scanner; public class a { public static void main(String[] args) throws SQLException, ClassNotFoundException { Scanner scanner = new Scanner(System.in); String id = scanner.nextLine(); String age = scanner.nextLine(); /* * 问题:注册两次驱动 * 解决:只想触发一次驱动 * 只触发静态代码块即可 * * */ /*方案1:*//* new Driver();*/ //方案2: Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?", "root", "080666"); Properties properties = new Properties(); properties.put("user", "root"); properties.put("password", "080666"); Connection connection1 = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", properties); Connection connection2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?user=root&password=080666"); Statement statement = connection1.createStatement(); String sql = "select * from students where id = "+id+" and age = "+age+";"; ResultSet resultSet = statement.executeQuery(sql); /* * 如果想进行数据解析,我们需要进行两件事情: * 1.移动游标指定获取数据行 * 2.获取指定数据行的列数据即可 * * 1.游标移动问题: * resultSet内部包含一个游标,指定当前换行数据 * 默认游标指定的是第一行数据 * 我们可以用next方法向后移动一行游标 * 如果我们有多行数据,我们可以使用while(next){获取每一行的数据} * boolean =next {} * true 有更多的数据,并且向下移动一行 * false 没有更多的数据,不一定 * * 如果next不满足我们的要求,是我们的查询条件出现问题了 * * 2.获取列的数据问题(获取光标指定的行的列的数据) * * resultSet.get类型(String columnLabel / int columnIndex) * columnLabel:列名 如果有别名 写别名 * columnIndex:列的下角标 从左往右 从1开始 * * while (resultSet.next()){ int id = resultSet.getInt("id"); String s = resultSet.getString(2); int password = resultSet.getInt("age"); System.out.println(id+" "+s+" "+password); } */ while (resultSet.next()){ int id1 = resultSet.getInt("id"); String s1 = resultSet.getString("name"); String gender = resultSet.getString("gender"); /* int anInt = resultSet.getInt("age");*/ String aClass = resultSet.getString("class"); System.out.println(id1+" "+s1+" "+gender+" "+" "+aClass); } resultSet.close(); statement.close(); connection1.close(); } }问题:SQL语句需要字符串拼接,比较麻烦
只能拼接字符串类型,其他的数据类型无法处理
可能发生注入攻击
动态值充当了sql语句结构,影响了原有的查询结果
核心API preparedstatement
package com.at; import javax.sql.DataSource; import java.sql.*; import java.util.Scanner; public class b { public static void main(String[] args) throws ClassNotFoundException, SQLException { Scanner scanner = new Scanner(System.in); String username = scanner.nextLine(); String password = scanner.nextLine(); Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb?useSSL=false&serverTimezone=UTC", "root", "080666"); /* * statement * 1.创建Statement * 2.拼接sql语句 * 3.发送sql语句,并获取返回结果 * * * preparedstatement * 1.编写sql语句结果 不包含动态值部分的语句,动态值部分使用占位符?替代 注意:?只能替代动态值 * 2.创建preparedstatement,并且传入动态值 * 3.动态值 占位符 赋值? 单独赋值即可 * 4.发送sql语句,并获取返回结果 * */ String sql="select * from students where id=? and age=?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setObject(1,username); preparedStatement.setObject(2,password); /* * 单独占位符进行赋值 * 参数1.index 占位符的位置 从左向右 从1开始 * 参数2.object 占位符的值 可以设置任何类型的数据,避免了我们拼接和类型更加丰富 * */ ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()){ System.out.println("登录成功"); } else System.out.println("登录失败"); resultSet.close(); preparedStatement.close(); connection.close(); } }核心API preparedstatement CRUD
package com.at; import org.testng.annotations.Test; import javax.sql.DataSource; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class c { @Test public void insert() throws Exception { Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", "root", "080666"); String sql="insert into students(id,name,gender,age,class) values (?,?,?,?,?);"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setObject(1, 1001); preparedStatement.setObject(2, "张三"); preparedStatement.setObject(3, "男"); preparedStatement.setObject(4, 18); preparedStatement.setObject(5, "1班"); int i = preparedStatement.executeUpdate(); if (i>0){ System.out.println("插入成功"); }else System.out.println("插入失败"); preparedStatement.close(); connection.close(); } @Test public void update() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", "root", "080666"); String sql = "update students set name=?,gender=?,age=?,class=? where id=?;"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setObject(1, "李四"); preparedStatement.setObject(2, "男"); preparedStatement.setObject(3, 19); preparedStatement.setObject(4, "2班"); preparedStatement.setObject(5, 1001); int i = preparedStatement.executeUpdate(); if (i > 0) { System.out.println("更新成功"); } else{ System.out.println("更新失败"); } preparedStatement.close(); connection.close(); } @Test public void delete() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", "root", "080666"); String sql = "delete from students where id=?;"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setObject(1, 1001); int i = preparedStatement.executeUpdate(); if (i > 0) { System.out.println("删除成功"); } else { System.out.println("删除失败"); preparedStatement.close(); connection.close(); } } @Test public void select() throws ClassNotFoundException, SQLException { } }//纯手动获取 @Test public void select() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", "root", "080666"); String sql = "select * from students;"; PreparedStatement preparedStatement = connection.prepareStatement(sql); ResultSet resultSet = preparedStatement.executeQuery(); List<Map> list = new ArrayList<>(); while (resultSet.next()) { Map map = new HashMap(); /*一行数据对应一个map*/ map.put("id", resultSet.getObject("id")); map.put("name", resultSet.getObject("name")); map.put("gender", resultSet.getObject("gender")); map.put("age", resultSet.getObject("age")); map.put("class", resultSet.getObject("class")); /*一行数据的所有列全部存到了map中*/ /*将map存储到集合中即可*/ list.add(map); } System.out.println(list); resultSet.close(); preparedStatement.close(); connection.close(); } /*自动*/ @Test public void select2() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", "root", "080666"); String sql = "select * from students;"; PreparedStatement preparedStatement = connection.prepareStatement(sql); ResultSet resultSet = preparedStatement.executeQuery(); ResultSetMetaData metaData = resultSet.getMetaData(); /*获取列的信息*/ /*获取当前结果集列的信息对象 也可以获取列的名称根据下角标,可以获取列的数量*/ int columnCount = metaData.getColumnCount(); /*有了他我们可以水平遍历列*/ List<Map> list = new ArrayList<>(); while (resultSet.next()) { Map map = new HashMap(); for (int i = 1; i <= columnCount; i++) { /*自动遍历序列,注意要从1开始,并且小于等于总列数*/ /*获取下角标的值 resultSet有关*/ Object value = resultSet.getObject(i); /*获取指定列的下角标的列的名称 resultSetMetaData*/ String columnLabel = metaData.getColumnLabel(i); map.put(columnLabel, value); } list.add(map); } System.out.println(list); } }扩展 主键回显和主键值获取
package com.at; import javax.sql.DataSource; import java.sql.*; public class d { public static void main(String[] args) throws Exception { Class.forName("com.mysql.cj.jdbc.Driver"); Connection root = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", "root", "080666"); String sql="insert into students(id,name,gender,age,class) values(?,?,?,?,?)"; PreparedStatement preparedStatement = root.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); preparedStatement.setObject(1, 102); preparedStatement.setObject(2, "张三"); preparedStatement.setObject(3, "男"); preparedStatement.setObject(4, 18); preparedStatement.setObject(5, "1班"); int i = preparedStatement.executeUpdate(); if (i > 0) { System.out.println("插入成功"); ResultSet generatedKeys = preparedStatement.getGeneratedKeys(); generatedKeys.next(); int anInt = generatedKeys.getInt(1); System.out.println(anInt); } else { System.out.println("插入失败"); } preparedStatement.close(); root.close(); } }扩展 批量插入数据优化
笨办法
package com.at; import javax.sql.DataSource; import java.sql.*; public class d { public static void main(String[] args) throws Exception { Class.forName("com.mysql.cj.jdbc.Driver"); Connection root = DriverManager.getConnection("jdbc:mysql://localhost:3306/studb", "root", "080666"); String sql="insert into students(id,name,gender,age,class) values(?,?,?,?,?)"; PreparedStatement preparedStatement = root.prepareStatement(sql); long start = System.currentTimeMillis(); for (int i = 1; i <=10000; i++) { preparedStatement.setObject(1, 102+i); preparedStatement.setObject(2, "张三"+i); preparedStatement.setObject(3, "男"+i); preparedStatement.setObject(4, 18+i); preparedStatement.setObject(5, "1班"+i); preparedStatement.executeUpdate(); } long end = System.currentTimeMillis(); long l = end - start; System.out.println(l); preparedStatement.close(); root.close(); } }批量插入
package com.at; import javax.sql.DataSource; import java.sql.*; public class d { public static void main(String[] args) throws Exception { Class.forName("com.mysql.cj.jdbc.Driver"); Connection root = DriverManager.getConnection( "jdbc:mysql://localhost:3306/studb?rewriteBatchedStatements=true", "root", "080666"); String sql = "insert into students(id,name,gender,age,class) values(?,?,?,?,?)"; PreparedStatement preparedStatement = root.prepareStatement(sql); long start = System.currentTimeMillis(); for (int i = 10001; i <= 20001; i++) { preparedStatement.setObject(1,10000+i); preparedStatement.setObject(2, "张三" + i); preparedStatement.setObject(3, "男" + i); preparedStatement.setObject(4, 18 + i); preparedStatement.setObject(5, "1班" + i); preparedStatement.addBatch();//不执行,追加到values的后面 } /* * 总结: * 路径后面添加?rewriteBatchedStatements=true 允许批量插入 * 不是执行语句每条,是批量添加addBatch() * 遍历添加完毕以后,统一执行executeBatch() * */ preparedStatement.executeBatch(); long end = System.currentTimeMillis(); long l = end - start; System.out.println(l); preparedStatement.close(); root.close(); } }事物回滚
数据库连接池的作用
无连接池的缺点:
1.不使用数据库连接池,每次都通过DriverManager获取新连接,用完直接抛弃断开,连接的利用率太低,太浪费。
2.对于数据库服务器来说,压力太大了,我们数据库服务器和java程序对连接数也无法控制,很容易导致数据库服务器崩溃。
我们希望能够管理连接:我们可以建立一个连接池,这个池可以容纳一定数量的连接对象,一开始,我们可以先替用户创建好一些连接对象,等用户要拿连接对象时,就直接从池中拿,不用新建了,这样就可以节省时间。然后用户用完之后就放回去,别人可以接着用。
可以提高连接的使用率,当池中的现有的连接用完了,那么连接池就可以向服务器申请新的连接池放到池中。
直到池中的连接达到最大连接数,就不能在申请新的连接了,如果没有拿到连接的用户只能等待。
连接池的使用
package com.at; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import com.alibaba.druid.pool.DruidPooledConnection; import org.testng.annotations.Test; import javax.sql.DataSource; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; public class druid { @Test public void test() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mysql://localhost:3306/studb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC"); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUsername("root"); dataSource.setPassword("080666"); Connection connection = dataSource.getConnection(); connection.close(); } /*通过读取外部配置文件的方法实例化druid连接池对象*/ @Test public void test2() throws Exception { Properties properties = new Properties(); properties.load(this.getClass().getClassLoader().getResourceAsStream("druid.properties")); DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); Connection connection = dataSource.getConnection(); String sql = "select * from students where id=?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setObject(1, 10001); ResultSet resultSet = preparedStatement.executeQuery(); List<Map> list = new ArrayList<>(); while (resultSet.next()) { Map map=new HashMap(); map.put("id",resultSet.getObject("id")); map.put("name",resultSet.getObject("name")); list.add(map); } System.out.println(list); } }工具类封装,分解步骤变成方法
高级应用封装BaseDao,封装非DQL操作
编程学习
技术分享
实战经验