当前位置:
首页 >
JDBC的应用
发布时间:2023/12/10
35
豆豆
JDBC
1. 概述:
JDBC - Java DataBase Connectivity Java数据库连接,
更简单的说就是Java语言操作数据库。
JDBC本质:其实是Sun公司定义的一套操作所有关
系型数据库的规则,即接口,各个厂商去实现这套接
口,提供数据库驱动Jar包,我们可以使用这套接口进行
编程,真正执行的代码是数据库驱动中的实现类。
其实这也是多态编程的优点:比如我调用了JDBC接
口中的一个getName()方法,实际执行会根据不同的驱
动,调用不同的方法。2. 快速入门
步骤:
1. 导入驱动Jar包
2. 注册驱动,让程序知道我们用的是哪个版本的驱动
3. 获取数据库连接对象 Connection
4. 定义SQL
5. 获取执行SQL语句的对象:Statement
6. 执行SQL,接收返回结果
7. 处理结果
8. 释放资源
1. 创建一个空Project
2. 在空项目中添加Module选择Java项目
选择存储路径3. 在项目中新建包 和 对应的快速入门演示案例类 4. 导入驱动jar包 在项目中添加一个文件夹,将驱动包复制到该包中,右 键---》 add as library...接下来就是代码部分 演示案例 数据库:CREATE DATABASE IF NOT EXISTS test CHARSET utf8; USE test; CREATE TABLE IF NOT EXISTS student( id INT,#学号 NAME VARCHAR(20),#姓名 age INT,#年龄 sex VARCHAR(5),#性别 address VARCHAR(100),#地址 math INT,#数学 english INT#英语 ); INSERT INTO student (id,NAME,age,sex,address,math,english) VALUES (1,'马云',18,'男','杭州',80,80), (2,'马化腾',19,'男','深圳',75,60), (3,'埃隆马斯克',31,'男','美国',76,93), (4,'扎克伯格',27,'男','美国',65,NULL), (5,'郎平',16,'女','上海',90,98), (6,'姚明',32,'男','上海',80,81); SELECT * FROM student; 测试案例: public class JdbcDemo1 {public static void main(String[] args) throws Exception { //1. 注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2.获取数据库连接对象 Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "root", "root"); //3.定义sql语句 String sql = "update student set english=90 where id = 4"; //4获取执行sql的对象 Statement statement = connection.createStatement(); //5.执行sql int count = statement.executeUpdate(sql); //6.处理结果 System.out.println(count); //7.释放资源 statement.close(); connection.close(); } }3. JDBC过程中的对象详解 3.1 Class.forName 疑问:这行代码获取到Class对象,却又不用变量接收, 这行代码有什么意义? 答:我们先去驱动包中找到Driver的源码 源码截图
JVM加载类的过程分为三步:加载,链接,初始 化。 在初始化这步,会执行类构造器方法clinit(),而 该方法是由变量的赋值动作 和 静态代码块的语句合并产 生的。也就是说 类的加载器在加载指定的类的时候,如 果该类结构中包含静态代码块,则会执行静态代码块中 的代码。因为JDBC的驱动有多种版本,所以JDBC规范中规 定,所有驱动都必须向驱动管理器注册以区分各个版 本。而Driver类 中只有一个无参构造 和 一个静态代码 块,静态代码块中的内容 刚好就是 驱动向驱动管理器注 册的代码。所以:Class.forName()的目的是加载 Driver类的时候向驱动管理器注册自己。 3.2 DriverManager : 驱动器管理对 象 功能: 1. 注册驱动(Class.forName()中已经解释):MySql5 之后的驱动Jar可以不注册驱动,它会自动帮我们注 册。 2. 获取数据库连接对象: 方法: DriverManager.getConnection("URL", "用户 名", "密码"); 参数: url:jdbc : mysql : // ip地址(域名):端口号 / 数 据库名称 注意:如果mysql是本机数据库且端口是默 认端口3306,则可以将ip地址(域名):端口 号部分省略jdbc:mysql:///test 用户名:连接mysql的用户名 密码:对应的密码 3.3 Connection : 数据库连接对象 功能: 1. 获取执行sql的对象 Statement createStatement() PreparedStatement prepareStatement(String sql) 2. 管理事务: 开启事务:void setAutoCommit(boolean autoCommit):调用该方法,参数为false,即开启 事务 提交事务:commit() 回滚事务: rollback() 3.4 Statement : 执行静态sql的对象 功能: 1. 执行 静态SQL 的对象 boolean execute(String sql) :可以执行任意的 sql (不常用)int executeUpdate(String sql) :执行 DML(insert、update、delete)语句、 DDL(create,alter、drop)语句 返回值int为影响行数可以作为语句是否执行成 功的判断标准:>0 成功 ResultSet executeQuery(String sql) :执行 DQL(select)语句 练习: 1. 给student表中增加一条记录 /** * 给student表中添加一条记录 */ public class JdbcDemo2 { public static void main(String[] args) { Statement statement = null; Connection connection = null; try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //获取连接对象connection = DriverManager.getConnection("jdbc:mysql://l ocalhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //编写sql String sql = "insert into student (id,name,age,sex,address,math,english) values(21,'呵呵',18,'男','杭州',80,80)"; //获取执行sql的对象 statement = connection.createStatement(); //执行sql int count = statement.executeUpdate(sql); //处理结果 if (count > 0) { System.out.println("添加成 功"); } else { System.out.println("添加失 败"); } } catch (Exception e) { e.printStackTrace(); }finally { try {if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) { se.printStackTrace(); } } } } 2.修改student表中的数据 /** * 修改表中的数据 */ public class JdbcDemo3 { public static void main(String[] args) { Statement statement = null; Connection connection = null; try { //注册驱动Class.forName("com.mysql.jdbc.Driver"); //获取连接对象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //编写sql String sql = "update student set name ='丁磊' where id=20"; //获取执行sql的对象 statement = connection.createStatement(); //执行sql int count = statement.executeUpdate(sql); //处理结果 if (count > 0) { System.out.println("修改成 功"); } else { System.out.println("修改失 败"); } } catch (Exception e) { e.printStackTrace(); }finally {3.5 ResultSet : 结果集对象 功能: 1. next(): 与Itrator迭代器的next()功能类似,将 游标移动到下一条记录。 起始位置在表头位置,所以 第一 次取数据需要先调用一次next()。 2. getXxx(参数):获取数据 Xxx: 代表数据类型:比如 int getInt() 参数: int : 代表列的编号,从1开始 try { if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) { se.printStackTrace(); } } } }String : 代表列名称:比如 getString("name") 演示案例1:取一条记录 /** * 查询表中数据,并取一条记录 */ public class JdbcDemo4 { public static void main(String[] args) { Statement statement = null; Connection connection = null; ResultSet resultSet = null; try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //获取连接对象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //编写sql String sql = "select * from student"; //获取执行sql的对象statement = connection.createStatement(); //执行sql resultSet = statement.executeQuery(sql); //处理结果 resultSet.next(); String name = resultSet.getString("name"); int age = resultSet.getInt("age"); System.out.println(name+"-- "+age); } catch (Exception e) { e.printStackTrace(); }finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) { se.printStackTrace(); } }} 演示案例2:遍历结果集 通过查询API,我们看到 next()方法 的返回值为 是否还有下一条数据:false:没有 true:有。那么我 们就可以根据next方法的返回值来作为循环的条件, 对结果集进行遍历 /** * 查询表中数据,遍历结果集 */ public class JdbcDemo5 { public static void main(String[] args) { Statement statement = null; Connection connection = null; ResultSet resultSet = null; try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //获取连接对象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root");//编写sql String sql = "select * from student"; //获取执行sql的对象 statement = connection.createStatement(); //执行sql resultSet = statement.executeQuery(sql); //处理结果 while (resultSet.next()) { String name = resultSet.getString("name"); int age = resultSet.getInt("age"); System.out.println(name+"--"+age); } } catch (Exception e) { e.printStackTrace(); }finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) {connection.close(); } } catch (SQLException se) { se.printStackTrace(); } } } } 演示案例3:查询Student表中所有数据,并将数据 存储到集合中 /** * 查询Student表中数据,并将所有数据存入到集合 中 */ public class JdbcDemo6 { public static void main(String[] args) { System.out.println(findAll()); } public static List<Student> findAll() { Statement statement = null; Connection connection = null; ResultSet resultSet = null;List<Student> list = new ArrayList<>(); try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //获取连接对象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //编写sql String sql = "select * from student"; //获取执行sql的对象 statement = connection.createStatement(); //执行sql resultSet = statement.executeQuery(sql); //处理结果集 while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name");int age = resultSet.getInt("age"); String sex = resultSet.getString("sex"); String address = resultSet.getString("address"); int math = resultSet.getInt("math"); int english = resultSet.getInt("english"); //封装对象 Student student = new Student(id, name, age, sex, address, math, english); list.add(student); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) {4. 抽取JDBC工具类 目的:简化书写 se.printStackTrace(); } } return list; } } import java.io.InputStream; import java.sql.Connection; import java.sql.Statement; import java.io.FileReader; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; /** * 简化JDBC操作的工具类 */public class JDBCUtils { //配置文件中的键对应的属性 private static String user; private static String password; private static String url; static{ //在静态代码块中读取配置信息,可以减少读取 次数 //读取配置文件 try { //1.创建Properties对象 Properties properties = new Properties(); //2.加载文件 ClassLoader classLoader = JDBCUtils.class.getClassLoader(); InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.prope rties"); properties.load(resourceAsStream); //获取值 url = properties.getProperty("url"); user = properties.getProperty("user");password = properties.getProperty("password"); //注册驱动 Class.forName(properties.getProperty("driv er")); } catch (Exception e) { e.printStackTrace(); } } /** * 获取连接对象 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } /** * 释放资源(增删改) * @param stmt 执行sql语句对象 * @param conn mysql连接对象*/ public static void close(Statement stmt, Connection conn) { if (stmt != null) { try { stmt.close(); } catch (SQLException se) { se.printStackTrace(); } } //两个异常处理不能写一起,因为一旦前面语句 出现异常,会导致后面资源不能正确被释放造成资源浪费 if (conn != null) { try { conn.close(); } catch (SQLException se) { se.printStackTrace(); } } } /** * 释放资源(查询) * @param stmt 执行sql语句对象 * @param conn mysql连接对象 * @param rs 存储查询结果集的对象 */ public static void close(Statement stmt, Connection conn, ResultSet rs) {if (stmt != null) { try { stmt.close(); } catch (SQLException se) { se.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException se) { se.printStackTrace(); } } if (rs != null) { try { rs.close(); } catch (SQLException se) { se.printStackTrace(); } } } } 注意1: 1. 抽取获取连接对象的方法时,如果使用用户传参的方 式与实际代码中获取连接对象的代码一致,达不到简化效果,所以我们将url,user,password , driver 抽取到配置文件中 2. 配置文件信息的读取涉及到IO流,所以应该是次数越 少越好,所以我们将读取配置文件 和 注册驱动这两 步放在静态代码块中,这样随着类的加载,配置文件 只需读取一次就可以有所有我们需要的信息。 演示案例:JDBC工具类使用 import org.wdzl.utils.JDBCUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * JDBCUtils使用:查询Student表中id = 2 的学生 信息 */ public class JdbcDemo7 { public static void main(String[] args) throws SQLException { //获取连接对象 Connection connection = JDBCUtils.getConnection(); //编写sql String sql = "select * from student where id=2";//获取statement对象 Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); //处理结果 while (resultSet.next()) { System.out.println(resultSet.getString("na me")); } //释放资源 JDBCUtils.close(statement,connection,resul tSet); } } 演示案例2:模拟登陆 分析: 1. 用户输入用户名,密码 2. 数据库查询是否有该信息 如果有,提示登录成功 如果没有,提示用户名或密码错误 3. 数据库表准备create table if not exists user( id int primary key auto_increment, username varchar(32) not null, password varchar(32) not null ) insert into user values(null,'test','test'); select * from user; 4. 测试案例 import org.wdzl.utils.JDBCUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; /** * 模拟用户登录 */ public class JdbcDemo8 { public static void main(String[] args) throws SQLException { Scanner sc = new Scanner(System.in);System.out.println("请输入用户 名:"); String username = sc.next(); System.out.println("请输入密码:"); String password = sc.next(); //登录 boolean flag = login(username, password); if (flag) { System.out.println("登录成 功"); } else { System.out.println("登录失 败"); } } /** * 登录方法 * @param username 用户名 * @param password 密码 * @return */ public static boolean login(String username, String password) throws SQLException { if (username != null && password != null) { //获取连接对象Connection connection = JDBCUtils.getConnection(); String sql = "select * from user where username='" + username + "' and password = '" + password + "'"; //获取指定sql的对象 Statement statement = connection.createStatement(); //执行sql ResultSet resultSet = statement.executeQuery(sql); //判断 return resultSet.next(); } return false; } } 这个案例中有一个很大的BUG: 在控制台输入密码时,我们这样输入,用户名 随 便输 a'or'a'='a 最终即便是密码用户名不匹配,依旧可以登录成功! 这就是我们常说的 SQL注入。 SQL注入:因为某些关键字参与SQL语句拼接导致出现安全问 题。 如何解决SQL注入: 使用 PreparedStatement 5. PreparedStatement: 执行 动态sql的对象 Statement 对象执行的sql 是在编译期就确定的 而PreparedStatement 执行的sql语句中,参数使 用?占位符替代,在执行时通过某些方法给相应的占位 符赋值才能获得完整的的SQL语句。这样就有效的防止 了SQL注入 步骤: 1. 导入驱动Jar包 2. 注册驱动,让程序知道我们用的是哪个版本的驱动 3. 获取数据库连接对象 Connection 4. 定义SQL,参数使用占位符 5. 获取执行动态SQL语句的对象PreparedStatement :Connection.PreparedStatement(String sql) 6. 给?占位符赋值 setXxx(参数1,参数2)参数1:?的位置编号,从1开始 参数2: ?对应的值 7. 执行SQL,接收返回结果,执行时不需要再传递sql语 句 8. 处理结果 9. 释放资源 演示案例:改进登录代码 /** * 登录方法 * @param username 用户名 * @param password 密码 * @return */ public static boolean login(String username, String password) throws SQLException { if (username != null && password != null) { //获取连接对象 Connection connection = JDBCUtils.getConnection(); String sql = "select * from user where username=? and password = ?"; System.out.println(sql); //获取指定sql的对象 PreparedStatement statement = connection.prepareStatement(sql);后期开发我们都使用PreparedStatement。因为它可 以防止SQL注入 6. JDBC 控制事务 6.1 事务: 一个包含多个步骤的业务操作。如果这个业务被事务管 理,则这多个步骤要么同时成功,要么同时失败。 6.2 事务操作 2. 提交事务 //设置?的值 statement.setString(1, username); statement.setString(2,password); //执行sql ResultSet resultSet = statement.executeQuery(); //判断 return resultSet.next(); } return false; } 1. 开启事务3. 回滚事务 6.3 使用Connection对象管理事务 1. 开启事务:void setAutoCommit(boolean autoCommit):调用该方法,参数为false,即开启 事务 获取Connection对象后即可开启事务 2. 提交事务:commit() 所有sql语句执行完毕后即可提交事务 3. 回滚事务: rollback() 只要捕获异常,就在catch中进行事务回滚 演示案例:JDBC控制事务 1. 准备数据库表 CREATE TABLE zhuanzhang( NAME VARCHAR(10), money DOUBLE(7,2) ); INSERT INTO zhuanzhang (NAME,money) VALUES ('张三',1000),('李四',1000); SELECT * FROM zhuanzhang; 2. 测试代码 import org.wdzl.utils.JDBCUtils;import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * JDBC 控制事务 */ public class JdbcDemo10 { public static void main(String[] args) throws SQLException { Connection connection = null; PreparedStatement stmt1 = null; PreparedStatement stmt2 = null; try { //获取连接 connection = JDBCUtils.getConnection(); //开启事务 connection.setAutoCommit(false); //定义sql //张三+500 String sql1 = "update zhuanzhang set money = money + ? where name = ?"; //李四-500String sql2 = "update zhuanzhang set money = money - ? where name = ?"; //获取执行sql对象 stmt1 = connection.prepareStatement(sql1); stmt2 = connection.prepareStatement(sql2); //设置参数 stmt1.setDouble(1, 500); stmt1.setString(2,"张三"); stmt2.setDouble(1, 500); stmt2.setString(2,"李四"); //执行更新 stmt1.execute();//更新操作不能 使用executeQuery()方法 //int a = 3 / 0;手动添加异常 stmt2.execute(); //提交事务 connection.commit(); } catch (Exception e) { if (connection != null) { connection.rollback(); } e.printStackTrace(); }finally { //释放资源7. 数据库连接池 数据库连接池类似于多线程种的线程池。 概述: 数据库连接池就是一个容器,存放了一些数据库连接 对象。 当系统初始化完成后,容器被创建,容器会申请一些 连接对象,当用户访问数据库时,从容器中获取连接对 象即可。访问完之后,会将连接对象归还给连接池。这 样做可以提高效率,提高连接对象的复用,不必频繁的 创建和释放连接对象。 实现: Java中提供了一个接口:javax . sql . DataSource。该接口是连接池技术的规范,具体实现 由数据库厂商实现。该接口中定义了两个方法: JDBCUtils.close(stmt1, connection); JDBCUtils.close(stmt2, null); } } }方法: 获取连接:getConnection() 归还连接:close() 。如果连接对象是从连接池中 获得,那么调用Connection.close()将不再关闭连 接,而 是归还连接。 连接池技术实现 C3P0 :数据库连接池技术 Druid: 由阿里巴巴提供的数据库连接池技术 7.1 C3P0连接池 步骤: 1. 导入Jar包 c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar 2. 定义配置文件: 规定名称:c3p0.properties 或者 c3p0- confifig.xml 规定路径:放在src目录下 3. 创建核心对象 :数据库连接池对象 ComboPooledDataSource 4. 获取连接: getConnection 演示案例:入门案例1. 新建一个Module ,在Module中新建lib目录,将jar包 拷贝的lib中,将配置文件拷贝到src下。不要忘记还 有mysql连接驱动jar包
2. 查看配置文件 c3p0-confifig.xml
3. 创建包和相应的演示案例类
package org.wdzl.datasource.c3p0; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; /** * C3P0演示案例 */ public class C3P0Demo1 { public static void main(String[] args) throws SQLException { //1.创建数据库连接池对象 DataSource dataSource = new ComboPooledDataSource(); //2. 获取连接对象 Connection connection = dataSource.getConnection(); //3. 查看连接对象 System.out.println(connection); //打印出对象信息就表示创建成功。 } }演示案例:配置参数演示 package org.wdzl.datasource.c3p0; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.junit.Test; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; /** * C3P0 配置参数演示案例 */ public class C3P0Demo2 { /* 验证 最大连接数 和 等待时间 */ @Test public void test() throws SQLException { //1.创建数据库连接池对象 DataSource dataSource = new ComboPooledDataSource(); //2. 获取连接对象:通过循环获取11个,前10 个都能获取,第11个等待3秒就会报错for (int i = 1; i <= 11; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); } } /* 验证 连接池的连接会被归还 */ @Test public void test2() throws SQLException { //1.创建数据库连接池对象 DataSource dataSource = new ComboPooledDataSource(); for (int i = 1; i <= 11; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); //归还第三次循环的连接对象,看被归还的对象 是否还出现 if (i == 3) { connection.close(); } } } /*指定配置信息:如果new ComboPooledDataSource()方法不传参数,则默认使用 配置文件中的default-config 如果指定字符串,使用指定名称的配置信息 */ @Test public void test3() throws SQLException { //1.创建数据库连接池对象 DataSource dataSource = new ComboPooledDataSource("otherc3p0"); for (int i = 1; i <= 10; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); } } } 7.2 Druid 连接池 - 目前公认最先进 的连接池技术 步骤: 1. 导包:druid-1.0.9.jar 2. 定义配置文件: 是properties形式的可以叫任意名称,可以放在任意目录下 3. 加载配置文件:Properties 4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory 5. 获取连接:getConnection 演示案例: 1. 将jar包拷入lib目录,将配置 druid.properties 文 件拷贝到src下 2. 创建包,在包中创建演示案例类
3. 测试案例 package org.wdzl.datasource.druid;import com.alibaba.druid.pool.DruidDataSourceFac tory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.util.Properties; /** * Druid 演示 */ public class DruidDemo1 { public static void main(String[] args) throws Exception { //加载配置文件 Properties properties = new Properties(); InputStream resourceAsStream = DruidDemo1.class.getClassLoader().getReso urceAsStream("druid.properties"); properties.load(resourceAsStream); //获取连接池对象 DataSource dataSource = DruidDataSourceFactory.createDataSource(p roperties); Connection connection = dataSource.getConnection();7.3 定义Druid 工具类 步骤: 1. 定义一个工具类:JDBCUtils 2. 提供静态代码块,加载配置文件,初始化连接池对象 3. 提供方法 获取连接的方法: 释放资源: 获取连接池的方法:因为有一些框架自己会通过连 接池获取连接对象。所以也需要提供这样一个方 法。 演示案例:JDBCUtils工具类 //查看连接对象 System.out.println(connection); } } package org.wdzl.datasource.utils; import com.alibaba.druid.pool.DruidDataSourceFacto ry; import com.mysql.jdbc.Statement;import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; /** * Druid连接池工具类 */ public class JDBCUtils { //成员变量 private static DataSource dataSource; static{ try { //1. 加载配置文件 Properties properties = new Properties(); properties.load(JDBCUtils.class.getClassLo ader().getResourceAsStream("druid.propertie s")); //2. 获取连接池对象 dataSource = DruidDataSourceFactory.createDataSource(pro perties); } catch (Exception e) { e.printStackTrace();} } /** * 获取连接对象 * @return 连接对象 */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } /** * 释放资源 * @param stmt 执行sql的对象 * @param conn 连接数据库的对象 */ public static void close(Statement stmt, Connection conn) { close(stmt,conn,null); } /** * 释放资源 * @param stmt 执行sql的对象 * @param conn 连接数据库的对象 * @param rs 查询结果集对象 */ public static void close(Statement stmt, Connection conn, ResultSet rs) {if (stmt != null) { try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (rs != null) { try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }/** * 获取连接池对象 * @return 连接池对象 */ public static DataSource getDataSource() { return dataSource; } } 演示案例2:使用工具类操作数据库 /** * 使用JDBC工具类操作数据库 */ public class DruidDemo2 { /* 向student表中添加一条数据 */ @Test public void test() throws SQLException { //1. 获取连接 Connection connection = JDBCUtils.getConnection(); //2.定义sql String sql = "insert into student (id,name,age,sex,address,math,english)" + " values(?,?,?,?,?,?,?)";8. Spring -JDBCTemplate 概述: Spring框架 对JDBC的简单封装,提供了一个 JDBCTemplate对象,来简化JDBC的开发。 步骤: //3. 获取执行sql的对象 PreparedStatement pst = connection.prepareStatement(sql); //4. 给占位符赋值 pst.setInt(1, 101); pst.setString(2,"哈哈"); pst.setInt(3, 20); pst.setString(4,"女"); pst.setString(5,"西安"); pst.setInt(6,100); pst.setInt(7,100); //5.执行 int count = pst.executeUpdate(); System.out.println(count); } }1. 导包:Spring的5个jar包,mysql连接驱动包,Druid 连接池jar包 2. 创建JdbcTemplate对象。依赖于数据源DataSource 3. 调用JdbcTemplate的方法来完成CRUD操作 update() : 执行DML语句。增,删,改语句。 queryForMap():查询结果,将结果封装为Map集 合 queryForList():查询结果,将结果集封装为List集 合 query():查询结果,将结果封装为JavaBean对象 queryForObject():查询结果,将结果封装为对象 练习中会对上述方法进行详细说明 入门案例: /** * JDBCTemplate 入门 * 新项目中我们需要使用JDBCTemplate, 我们需要先 添加Druid连接池的jar包和配置文件,添加JDBCUtiles 工具类,才能使用JDBCTemplate。 */ public class JDBCTemplateDemo { public static void main(String[] args) { //1. 创建JDBCTemplate对象 JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); //2.调用方法使用JDBCTemplate操作数据库只关心sql的编写 和 执 行,其他的操作JDBCTemplate都会替我们完成。 演示案例:DML,DQL语句 需求:使用Student表,将Student实体类复制到当前工 程中 1. 修改id为3 的学生数据,将 age改为 30 2. 添加一条记录 3. 删除刚才添加的记录 4. 查询id为3的记录,将其封装为Map集合 5. 查询所有记录,将其封装为List集合 6. 查询所有记录,将其封装为Student对象的List 集合 7. 查询name="埃隆马斯克" 的学生信息,并封装 成Student对象 String sql = "update student set sex=?,address=? where id=?"; // 有几个?,就在update()方法中传几个参 数即可。 int update = template.update(sql, "男", "太原", 20); System.out.println(update); } } import org.junit.Test;import org.springframework.jdbc.core.BeanPropertyR owMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.wdzl.datasource.utils.JDBCUtils; import org.wdzl.pojo.Student; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.Map; /** * JDBCTemplate 入门 */ public class JDBCTemplateDemo2 { //方便使用 private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); /* 修改id为3 的学生数据,将 age改为 30 */ @Test public void test() { //1.获取连接对象 // JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());//2.编写sql String sql = "update student set age=? where id=?"; //3.执行sql,给占位符赋值 int update = template.update(sql, 30, 3); System.out.println(update); } /* 添加一条记录 */ @Test public void test2() { //2.编写sql String sql = "insert into student values(?,?,?,?,?,?,?)"; //3. 执行 int update = template.update(sql, 22, "刘德华", 25, "男", "香港", 80, 75); System.out.println(update); } /* 删除刚添加的记录 */ @Test public void test3() { String sql = "delete from student where id=?";int update = template.update(sql, 22); System.out.println(update); } /* 查询id为3的记录,将其封装为Map集合 queryForMap():将记录的字段名作为键,字段值作 为值封装到map集合中。 map格式 : 字段名 = 字段值 注意: 结果集长度只能是1 超过则会报错 */ @Test public void test4() { String sql = "select * from student where id=?"; Map<String, Object> map = template.queryForMap(sql, 3); // String sql = "select * from student where id=? or id=?"; // Map<String, Object> map = template.queryForMap(sql, 3,4);//报错,因为记 录超过两条 System.out.println(map); } /* 查询所有记录,将其封装为List集合 queryForList():将每一条记录封装到map集合, 再把每一条记录的map集合存入list集合*/ @Test public void test5() { String sql = "select * from student"; List<Map<String, Object>> maps = template.queryForList(sql); for (Map<String, Object> map : maps) { System.out.println(map); } } /* 查询所有记录,将其封装为Student对象的 List集合--方式1 template.query(sql, new RowMapper<Student>() {mapRow()}); 该方法需要自己实现一个接口,每查询一条记录 就会执行一次接口里面的mapRow()方法,将结果进行封装 */ @Test public void test6() { String sql = "select * from student"; List<Student> students = template.query(sql, new RowMapper<Student> () { @Overridepublic Student mapRow(ResultSet resultSet, int i) throws SQLException { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); int age = resultSet.getInt("age"); String sex = resultSet.getString("sex"); String address = resultSet.getString("address"); int math = resultSet.getInt("math"); int english = resultSet.getInt("english"); Student student = new Student(id, name, age, sex, address, math, english); return student; } }); //遍历集合 for (Student student : students) { System.out.println(student); } } /*查询所有记录,将其封装为Student对象的List 集合-方式2 template.query(sql,new BeanPropertyRowMapper<实体类>(实体类.class)) 注意:如果用方式2,你的实体类中属性的基本数 据类型一定要定义成包装类型,否则如果你的查询记录中有 null的话 会报错,因为 基本数据类型中不能存null */ @Test public void test6_2() { String sql = "select * from student"; List<Student> students = template.query(sql,new BeanPropertyRowMapper<Student> (Student.class)); //遍历集合 for (Student student : students) { System.out.println(student); } } /* 查询name="埃隆马斯克" 的学生信息,并封装成 Student对象queryForObject(sql,new BeanPropertyRowMapper<>(封装的实体类.class), 参数) */ @Test public void test7() { String sql = "select * from student where name=?"; Student student = template.queryForObject(sql, new BeanPropertyRowMapper<>(Student.class),"埃隆 马斯克"); System.out.println(student); } }
总结
- 上一篇: Louvain算法实现
- 下一篇: Accusoft结构化工具包FormSu