JDBC基本介绍

image.png
image.png
image.png
image.png

获取connection的方式

image.png
image.png TIP:把这个选中取消可以让文件夹分层
前置工作:在项目下创建一个文件夹比如libs, 将 mysql.jar 拷贝到该目录下,点击 add as library
在mysql官网上下载连接的jar包_18你磊哥的博客-CSDN博客 mysql.jar包下载教程
image.png

第一种(操作完整版)

  1. import java.sql.*;
  2. import java.util.Properties;
  3. import com.mysql.cj.jdbc.Driver; //注意引这个 新版有cj
  4. public class Jdbc01{
  5. public static void main(String[] args) throws Exception{
  6. //1.注册驱动
  7. Driver driver = new Driver();
  8. //2.得到连接 (mysql的连接本质就是socket连接)
  9. String url = "jdbc:mysql://localhost:3306/shang_02";
  10. // jdbc:mysql:// 规定好表示协议,通过jdbc的方式连接mysql
  11. // localhost 主机,可以是ip地址
  12. // 3306 表示mysql监听的端口号
  13. // shang_02 连接到mysql的哪个数据库
  14. //3.将用户名和密码放入到Properties对象,用url和properties得到连接
  15. Properties properties = new Properties();
  16. properties.setProperty("user","root"); //用户
  17. properties.setProperty("password","shang"); //密码
  18. Connection connection = driver.connect(url,properties);
  19. //4.执行sql (用statement)
  20. String sql = "insert into t01 values('张三',21)";
  21. Statement statement = connection.createStatement();
  22. int rows = statement.executeUpdate(sql);
  23. //如果是dml语句,返回的就是影响行数
  24. System.out.println(rows>0?"成功":"失败");
  25. //5.关闭连接资源
  26. statement.close();
  27. connection.close();
  28. }
  29. }

第二种

  1. public void connect02() throws Exception{
  2. //使用反射加载Driver类,动态加载,更加灵活,减少依赖性
  3. Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
  4. Driver dirver = (Driver)aClass.newInstance();
  5. ...//后面就一样了
  6. }

第三种

  1. public void connect03() throws Exception{
  2. //用DriverManager替代Driver
  3. Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
  4. Driver driver = (Driver) aClass.newInstance();
  5. //创建url,user和password
  6. String url = "jdbc:mysql://localhost:3306/shang_02";
  7. String user = "root";
  8. String password = "shang";
  9. //注册Driver驱动
  10. DriverManager.registerDriver(driver);
  11. Connection connection = DriverManager.getConnection(url,user,password);
  12. }

第四种(第三种的极简版本)

自动完成注册,简化代码

  1. public void connect04() throws Exception{
  2. //Class.forName("import com.mysql.cj.jdbc.Driver");
  3. //创建url,user和password
  4. String url = "jdbc:mysql://localhost:3306/shang_02";
  5. String user = "root";
  6. String password = "shang";
  7. Connection connection = DriverManager.getConnection(url,user,password);
  8. System.out.println(connection);
  9. }

注:
1. 调用DriverManager的getConnection方法,直接获取连接,不用生成Driver。
2. 并且mysql驱动5.1.6可以无需Class.forName(“…”),但还是建议写上,更加明确。
3. register那句代码省略,因为Driver类在加载时,它源码的静态代码块已经注册过DriverManager了

第五种

增加配置文件,让连接mysql更加灵活
image.png
注意:都不加双引号!

  1. public void connect05() throws Exception{
  2. //通过Properties对象获取配置文件的信息
  3. Properties properties = new Properties();
  4. properties.load(new FileInputStream("D:\\JavaProject\\Hello\\src\\mysql.properties"));
  5. //获取相关的值
  6. String user = properties.getProperty("user");
  7. String password = properties.getProperty("password");
  8. String url = properties.getProperty("url");
  9. String driver = properties.getProperty("driver");
  10. Class.forName(driver); //建议写上
  11. Connection connection = DriverManager.getConnection(url,user,password);
  12. System.out.println(connection);
  13. }

image.png

ResultSet 结果集

image.png

  1. ...
  2. //获取connection的五种方法
  3. //得到statement
  4. Statement statement = connection.createStatement();
  5. //sql指令
  6. String sql = "select * from t01";
  7. //获取resultSet
  8. ResultSet resultSet = statement.executeQuery(sql);
  9. //使用while取出数据
  10. while(resultSet.next()) { //让光标向后移动,如果没有更多行,则返回false
  11. String name = resultSet.getString(1); //获取该行第一列
  12. int age = resultSet.getInt(2); //获取该行第二列
  13. System.out.println(name + "\t" + age);
  14. }
  15. //关闭连接
  16. connection.close();
  17. statement.close();
  18. resultSet.close();

image.pngimage.png

Statement

image.png

SQL注入

输入用户名为 1’ OR
输入密码为 OR ‘1’ = ‘1

  1. SELECT *
  2. FROM admin
  3. WHERE NAME = '1' OR ' AND pwd = ' OR '1' = '1'

最终机器会执行为 : WHERE NAME = ‘1’ OR ‘ AND pwd = ‘ OR ‘1’ = ‘1’ 也即中间有两个OR
但是 ‘1’ = ‘1’ 是绝对正确的,因此会恶意攻击数据库。

PreparedStatement

image.png

  1. public static void main(String[] args) throws Exception{
  2. Scanner scanner = new Scanner(System.in);
  3. System.out.print("请输入管理员的名字:");
  4. String admin_name = scanner.nextLine(); //next遇到空格会结束
  5. System.out.println("请输入管理员的密码:");
  6. String admin_pwd = scanner.nextLine();
  7. ...//获取connection
  8. //得到PreparedStatement
  9. //1. 组织SQL,?相当于占位符
  10. String sql = "select name,pwd from admin where name =? and pwd =?";
  11. //2. 获取对象
  12. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  13. //3. 给?赋值
  14. preparedStatement.setString(1,admin_name);//第一个问号
  15. preparedStatement.setString(2,admin_pwd);
  16. //4. 执行select语句使用 executeQuery dml语句用 executeUpdate
  17. ResultSet resultSet = preparedStatement.executeQuery(sql);
  18. ...//while循环查看
  19. }

dml语句:
image.png

JDBC API

image.png
image.pngimage.png

JDBC工具类

image.pngimage.png

属性

  1. private static String user;
  2. private static String password;
  3. private static String url;
  4. private static String driver;

初始化

  1. //在static代码块中初始化
  2. static {
  3. try {
  4. Properties properties = new Properties();
  5. properties.load(new FileInputStream("D://JavaProject//Hello//src//mysql.properties"));
  6. user = properties.getProperty("user");
  7. password = properties.getProperty("password");
  8. url = properties.getProperty("url");
  9. driver = properties.getProperty("driver");
  10. } catch (IOException e) {
  11. //在实际开发中,我们经常把编译异常转换成运行异常
  12. //这样调用者可以选择捕获该异常,也可以选择默认处理该异常
  13. throw new RuntimeException(e);
  14. }
  15. }

获取Connection方法

  1. //连接数据库,返回Connection
  2. public static Connection getConnection(){
  3. try {
  4. return DriverManager.getConnection(url,user,password);
  5. } catch (SQLException e) {
  6. throw new RuntimeException(e);
  7. }
  8. }

关闭资源方法

  1. //关闭相关资源
  2. /*
  3. 1.ResultSet结果集
  4. 2.Statement 或者 PreparedStatement
  5. 3.Connection
  6. 4.如果需要关闭资源,就传入对象,否则传入null
  7. */
  8. public static void close(ResultSet set, Statement statement,Connection connection){
  9. try {
  10. if(set!=null){
  11. set.close();
  12. }
  13. if(statement!=null){
  14. statement.close();
  15. }
  16. if(connection!=null){
  17. connection.close();
  18. }
  19. } catch (SQLException e) {
  20. throw new RuntimeException(e);
  21. }
  22. }

工具类的使用

DML语句

  1. public class JDBCUtils_DML {
  2. public static void main(String[] args) {
  3. //1.得到连接
  4. Connection connection = null;
  5. //2.组织一个sql
  6. String sql = "update t01 set age = ? where name = ?";
  7. //3.创建PreparedStatement对象
  8. PreparedStatement preparedStatement = null;
  9. try {
  10. connection = JDBCUtils.getConnection();
  11. preparedStatement = connection.prepareStatement(sql);
  12. //给占位符赋值
  13. preparedStatement.setInt(1,18);
  14. preparedStatement.setString(2,"张三");
  15. //把"张三"修改为18岁,执行
  16. preparedStatement.executeUpdate();
  17. } catch (SQLException e) {
  18. e.printStackTrace();
  19. } finally {
  20. JDBCUtils.close(null,preparedStatement,connection);
  21. }
  22. }
  23. }

Select语句

  1. public static void main(String[] args) {
  2. //1.得到连接
  3. Connection connection = null;
  4. //2.组织一个sql
  5. String sql = "select * from t01";
  6. //3.创建PreparedStatement对象
  7. PreparedStatement preparedStatement = null;
  8. //4.创建ResultSet对象
  9. ResultSet resultSet = null;
  10. try {
  11. connection = JDBCUtils.getConnection();
  12. preparedStatement = connection.prepareStatement(sql);
  13. resultSet = preparedStatement.executeQuery();
  14. while(resultSet.next()){ //while循环读取
  15. String name = resultSet.getString("name");
  16. int age = resultSet.getInt("age");
  17. System.out.println(name + "\t" + age);
  18. }
  19. } catch (SQLException e) {
  20. e.printStackTrace();
  21. } finally {
  22. JDBCUtils.close(resultSet,preparedStatement,connection);
  23. }
  24. }

事务

image.png
setAutoCommit相当于开启一个事务,rollback默认返回开启事务的地方。

批处理

image.png

  1. public void batch() throws Exception{
  2. Connection connection = JDBCUtils.getConnection(); //获取链接
  3. String sql = "insert into t01 values(?,?)"; //sql语句
  4. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  5. for(int i = 0;i<5000;i++){
  6. preparedStatement.setString(1,"jack"+i);
  7. preparedStatement.setInt(2,18+i);
  8. //将sql语句加入到批处理包中
  9. preparedStatement.addBatch();
  10. //当有1000条记录时,批量执行
  11. if((i+1)%1000==0){
  12. preparedStatement.executeBatch(); //执行
  13. //清空
  14. preparedStatement.clearBatch();
  15. }
  16. }
  17. JDBCUtils.close(null,preparedStatement,connection);
  18. }

如果想成功使用批处理,url需要加上?后面的语句:

  1. url=jdbc:mysql://localhost:3306/shang_02?rewriteBatchedStatements=true

1. 底层创建了 ArrayList,名字为elementData,是Object数组,存放我们预处理的sql语句。
2. 当elementData满后,就按照1.5倍扩容。
3. 批量处理会减少我们发送sql语句的网络开销,而且减少编译次数,因此效率提高。

数据库连接池

传统获取Connection问题分析

image.png

数据库连接池介绍

image.png
image.pngimage.png

数据库连接池种类

image.png
主要了解C3P0以及Druid。

C3P0

前期准备

下载参考:C3P0jar包下载方法_小猪的日常Java-CSDN博客_c3p0jar包下载 类似connector,我们需要把 c3p0-0.9.5.5.jar(可以变化) 加入到项目中(add to library),如果最后连接失败,一直提示 java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector
解决方法:把 mchange-commons-java-0.2.19.jar 也导入项目中
另外还需要在src目录下导入 c3p0-config.xml,注意这个文件是自己写的,详细可以看这个博客
c3p0详细配置(c3p0-config.xml)及使用_caychen的博客-CSDN博客_c3p0-config.xml
image.png 最后差不多是这样,jar和xml是必须导入的

实例代码

第一种方式:不使用 c3p0-config.xml (不推荐,代码太多了)

  1. public static void main(String[] args) throws Exception{
  2. //1.创建一个数据源对象
  3. ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
  4. //2.通过配置文件properties获取相关连接的信息
  5. Properties properties = new Properties();
  6. properties.load(new FileInputStream("D://JavaProject//Hello//src//mysql.properties"));
  7. //3.读取相关属性值
  8. String user = properties.getProperty("user");
  9. String password = properties.getProperty("password");
  10. String url = properties.getProperty("url");
  11. String driver = properties.getProperty("driver");
  12. //4.给数据源 comboPooledDataSource 设置相关的参数
  13. comboPooledDataSource.setDriverClass(driver);
  14. comboPooledDataSource.setJdbcUrl(url);
  15. comboPooledDataSource.setUser(user);
  16. comboPooledDataSource.setPassword(password);
  17. //设置初始化连接数
  18. comboPooledDataSource.setInitialPoolSize(10);
  19. //设置最大连接数
  20. comboPooledDataSource.setMaxPoolSize(50);
  21. //5.连接
  22. Connection connection = comboPooledDataSource.getConnection();
  23. System.out.println("连接OK");
  24. }

第二种方式:使用 c3p0.config.xml ,该文件指定了连接数据库和连接池的相关参数
注意需要写上 用来指定连接池的名字,才能用。

  1. public static void main(String[] args) throws Exception{
  2. ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("SHANG");
  3. Connection connection = comboPooledDataSource.getConnection();
  4. System.out.println("连接OK");
  5. }

Druid

前期准备

下载druid.jar和druid.properties,加入到项目中。
image.png druid.jar加入到libs文件夹,然后add to library,properties文件直接放在src根目录下。 至于怎么设置上网看就行了。

连接代码

  1. public static void main(String[] args) throws Exception{
  2. //1.加入 druid.jar 包
  3. //2.加入配置文件 druid.properties,将该文件拷贝到项目的src目录
  4. //3.创建Properties对象,读取配置文件
  5. Properties properties = new Properties();
  6. properties.load(new FileInputStream("D:\\JavaProject\\Hello\\src\\druid.properties"));
  7. //4.创建一个指定参数的数据库连接池
  8. DataSource dataSource =
  9. DruidDataSourceFactory.createDataSource(properties);
  10. //5.连接
  11. Connection connection = dataSource.getConnection();
  12. }

注:不管是哪个properties,里面的 driverClassName 必须写成 com.mysql.cj.jdbc.Driver (老版本是没有 cj 的)

基于Druid连接池的工具类

  1. public class JDBCUtilsByDruid{
  2. private static DataSource ds;
  3. //在静态代码块完成ds初始化
  4. static{
  5. Properties properties = new Properties();
  6. try {
  7. properties.load(new FileInputStream("D:\\JavaProject\\Hello\\src\\druid.properties"));
  8. ds = DruidDataSourceFactory.createDataSource(properties);
  9. } catch (Exception e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. //getConnection方法
  14. public static Connection getConnection() throws SQLException {
  15. return ds.getConnection();
  16. }
  17. //关闭连接方法 (注意在连接池技术中,close不是断掉连接,而是把Connection对象放回连接池)
  18. public static void close(ResultSet set, Statement statement,Connection connection) throws SQLException {
  19. if(set!=null){
  20. set.close();
  21. }
  22. if(statement!=null){
  23. statement.close();
  24. }
  25. if(connection!=null){
  26. connection.close();
  27. }
  28. }
  29. }

Apache-DBUtils

由于关闭connection后,resultSet结果集就无法使用了,因此不利于数据的管理。但如果把表中的内容(一行)看作对象,把行放入一个ArrayList,就不用管resultSet能不能使用了
image.png
image.png

Select使用

DBUtils相关的jar下载地址:
DbUtils jar包下载_小猪的日常Java-CSDN博客_dbutils jar包

  1. public class Person {
  2. private String name;
  3. private int age;
  4. } //内容与表保持一致
  1. public static void main(String[] args) throws Exception{
  2. //1.得到连接
  3. Connection connection = JDBCUtilsByDruid.getConnection();
  4. //2.使用DBUtils类和接口,需要引入DBUtils相关的jar
  5. //3.创建 QueryRunner
  6. QueryRunner queryRunner = new QueryRunner();
  7. String sql = "select * from t01 where name = ?";
  8. //用相关方法返回ArrayList结果集
  9. List<Person> list =
  10. queryRunner.query(connection,sql,new BeanListHandler<>(Person.class),"张三");
  11. for (Person person : list) {
  12. System.out.println(person);
  13. }
  14. JDBCUtilsByDruid.close(null,null,connection);
  15. }

注:
1. query方法就是执行sql语句,得到resultSet,然后封装到 ArrayList集合中。
2. connection 连接,sql 执行的sql语句,new BeanListHandler<>(Person.class):底层使用反射机制去获取Person类的属性,将resultSet封装到ArrayList中(用于多行多列输出)。
3. 调用完方法后面的就是写入?的参数。

如果返回的是单个Person对象(不用使用集合),这时使用的是 BeanHandler方法。

  1. Person person =
  2. queryRunner.query(connection,sql,new BeanHandler<>(Person.class),"...");

如果返回的是单行单列(返回一个Object),这时使用的是 ScalarHandler方法。

  1. Object obj = queryRunner.query(connection,sql,new ScalarHandler<>(),"...");


DML使用

  1. public static void main(String[] args) throws Exception {
  2. //1.得到连接
  3. Connection connection = JDBCUtilsByDruid.getConnection();
  4. //2.创建QueryRunner
  5. QueryRunner queryRunner = new QueryRunner();
  6. //4.组织sql
  7. String sql = "update t01 set name = ? where age = ?";
  8. //String sql = "insert into t01 values(?,?)";
  9. //String sql = "delect from t01 where name = ?";
  10. int affectRows = queryRunner.update(connection, sql, "王五", 22);
  11. JDBCUtilsByDruid.close(null, null, connection);
  12. }

注:执行dml操作的是 queryRunner.update(),返回的值是受影响的行数。

DAO

image.png
image.png

DAO的一些结构

image.png
image.png
image.png
image.png

BasicDAO

  1. public class BasicDAO<T> { //泛型指定具体类型
  2. private QueryRunner qr = new QueryRunner(); //属性

开发通用的dml方法

针对任意的表

  1. //开发通用的dml方法,针对任意的表
  2. public int update(String sql,Object... parameters) throws SQLException {
  3. Connection connection = null;
  4. try {
  5. connection = JDBCUtilsByDruid.getConnection(); //得到连接
  6. int update = qr.update(connection,sql,parameters); //得到修改的行数
  7. return update;
  8. } catch (SQLException e) {
  9. throw new RuntimeException();
  10. } finally {
  11. JDBCUtilsByDruid.close(null,null,connection); //关闭连接
  12. }
  13. }

查询方法(返回多行多列)

  1. public List<T> queryMulti(String sql,Class<T> clazz,Object... parameters) throws SQLException {
  2. Connection connection = null;
  3. List<T> query = null;
  4. try {
  5. connection = JDBCUtilsByDruid.getConnection();
  6. query = qr.query(connection,sql,new BeanListHandler<T>(clazz),parameters);
  7. } catch (SQLException e) {
  8. throw new RuntimeException();
  9. } finally {
  10. JDBCUtilsByDruid.close(null,null,connection);
  11. }
  12. return query;
  13. }

对形参的解释:
sql:sql语句,可以有?
clazz:传入一个类的Class对象,比如Person.class
parameters:给?赋值

查询(返回一行)

  1. //查询单行结果的通用方法
  2. public T querySingle(String sql,Class<T> clazz,Object... parameters) throws SQLException {
  3. Connection connection = null;
  4. try {
  5. connection = JDBCUtils.getConnection();
  6. return qr.query(connection,sql,new BeanHandler<T>(clazz),parameters);
  7. //使用 BeanHandler方法
  8. } catch (SQLException e) {
  9. throw new RuntimeException();
  10. } finally {
  11. JDBCUtilsByDruid.close(null,null,connection);
  12. }
  13. }

查询(返回单行单列)

  1. //查询单行单列的方法,即返回单值的方法
  2. public Object queryScalar(String sql,Object... parameters) throws SQLException {
  3. Connection connection = null;
  4. try {
  5. connection = JDBCUtilsByDruid.getConnection();
  6. return qr.query(connection,sql,new ScalarHandler(),parameters);
  7. //使用ScalarHandler方法
  8. } catch (SQLException e) {
  9. throw new RuntimeException();
  10. } finally {
  11. JDBCUtilsByDruid.close(null,null,connection);
  12. }
  13. }

PersonDAO

Person是映射表内容的类,PersonDAO需要继承BasicDAO,然后在里面写入自己的独特内容。

  1. public class PersonDAO extends BasicDAO{
  2. //继承BasicDAO,在这里面写独特的内容
  3. private String name;
  4. private int age;
  5. }

TestDAO

测试PersonDAO对t01表的查找操作

  1. public void testPersonDAO() throws SQLException {
  2. PersonDAO personDAO = new PersonDAO();
  3. List<Person> list = personDAO.queryMulti("select * from t01 where age=?",Person.class,18);
  4. System.out.println("查询结果为");
  5. for (Person person : list) {
  6. System.out.println(person);
  7. }
  8. }

testWhileIdle is true, validationQuery not set解决方法 :
严重: testWhileIdle is true, validationQuery not set 使用Druid连接池报错处理【无Spring框架,使用的JDK9,MYSQL8版本】_Syntacticsugar’s blog-CSDN博客_test-while-idle

dml操作

  1. public void testPersonDAO() throws SQLException {
  2. PersonDAO personDAO = new PersonDAO();
  3. personDAO.update("insert into t01 values(?,?)","Hans",22);
  4. }