JDBC学习笔记

JDBC

1、基本概念

2、快速入门

package club.suhai.jdbc_demo;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

//JDBC快速入门
public class JdbcDem01 {
  public static void main(String[] args) {
    // 1.导入jar包到libs目录下
      try {
          Class.forName("com.mysql.jdbc.Driver");
          // 3.获取数据库链接对象
          try {
              Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "0610");
              // 4.定义sql语句
              String sql = "update stu set age = 99 where id = 1";
              // 5.获取执行sql的对象 statement
              Statement statement = connection.createStatement();
              // 6.执行sql
              int age = statement.executeUpdate(sql);
              // 7.处理结果
              System.out.println(age);
              // 8.释放资源
              statement.close();
              connection.close();
          } catch (SQLException throwables) {
              throwables.printStackTrace();
          }

      } catch (ClassNotFoundException e) {
          e.printStackTrace();
      }
  }
}

2、1 详解各个对象

1. DriverManager:驱动管理对象

 1、DriverManager:驱动管理对象
      功能:1.注册驱动://告诉程序该使用哪一个数据库驱动jar包
      	public static void registerDriver​(Driver driver) throws SQLException
      	//使用DriverManager注册给定的驱动程序
      	2.获取数据库连接
      	 public static Connection getConnection(String url,
          String user, String password)
      	url: 指定连接路径 jdbc:mysql://localhost(域名):3306(端口号)/数据库名
  	    user: 数据库用户名
          password: 数据库用户密码
  	   连接本地数据库:url 可以简写:jdbc:mysql:///数据库名称

2、Connection:数据库连接对象

  2、Connection:数据库连接对象
      	1.功能:获取执行sql的对象
      		Statement createStatement();
  		    PreParedStatement preparedStatement(String sql);
      	2.管理事务
              开启事务:
  				void setAutoCommit​(boolean autoCommit) 将此连接的自动提交模式设置为给定状态。 
              提交事务:
  				void commit() 使自上次提交/回滚以来所做的所有更改成为永久更改,并释放此 Connection对象当前持有的所有数据库锁。  
              回滚事务:void rollback() 撤消当前事务中所做的所有更改,并释放此 Connection对象当前持有的所有数据库锁。  

3、Statement:执行sql的对象

 3、Statement:执行sql的对象(不安全,实际并不会使用)
           1.执行sql:
  		    1.1 boolean execute​(String sql) 执行给定的SQL语句,该语句可能返回多个结果。  
            1.2(常用)int executeUpdate​(String sql) 执行给定的SQL语句,这可能是 INSERT , UPDATE ,或 DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。
                  	参数 
                          sql -一个SQL数据操纵语言(DML)语句,比如INSERT , UPDATE或DELETE ; 或者不返回任何内容的SQL语句,例如DDL语句。 
                      返回结果 
                          //(1)SQL数据操作语言(DML)语句的行数 ---判断是否执行成功
                          //(2)0表示不返回任何内容的SQL语句 
                              
  		   1.3ResultSet executeQuery​(String sql) 执行给定的SQL语句,该语句返回单个 ResultSet对象。

4、ResultSet:结果集对象 //封装查询结果

  	  4、ResultSet:结果集对象 //封装查询结果
              1.boolean next() 将光标从当前位置向前移动一行。  
              2.getXXX(参数):获取数据
                      // XXX代表你要获取数据的数据类型 
                          如:  
                              //获取结果集id
                              int id = resultSet.getInt(1);
                              //获取结果集name
                              String name = resultSet.getString("name");
                              //获取结果集acount
                              double acount = resultSet.getDouble(3);
  					  参数:
                            	int :代表列的编号,从1开始,如getString(1);
  						  String:代表列名称,如 getDouble("account");
  		   3.注意:
                 使用步骤:
                           1.游标向下移动一行
                 		    2.判断是否有数据
                 		    3.获取数据
                  //循环判断游标是否是最后一行末尾
                  while (resultSet.next()){
                      //获取结果集id
                      int id = resultSet.getInt(1); //参数 1 代表获取第一列的id
                      //获取结果集name
                      String name = resultSet.getString("name");//参数 name 代表获取列名为 name 的数据
                      //获取结果集acount
                      double acount = resultSet.getDouble(3);
                      System.out.println(id+"---"+name+"---"+acount);
                  }
  		  4.小练习
                //定义一个方法,查询emp表的数据,并将其封装成对象,然后装在集合,返回
                4.1 定义一个emp类
                4.2 定义方法 public List<Emp> findAll();
  			   4.3 实现方法 select *from emp;
                                  

5、PreparedStatement:执行sql的对象

 5、PreParedStatement:执行sql的对象
      		 1.SQL注入问题:在拼接sql时有一些sql特殊关键字参与字符串的拼接,会造成安全性问题
      				1.输入用户随便,输入密码:a' or 'a' = 'a
      					  请输入用户名:
                              adadad
                              请输入用户密码:
                              a' or 'a' = 'a
                              /E:/WorkSpace/JDBCDemo/out/production/JDBCDemo/jdbc.properties
                              select * from user where username = 'adadad' and password = 'a' or 'a' = 'a' 
                              恭喜您adadad登录成功!
             2.解决SQL注入问题:使用PreparedStatement对象来解决
             3.预编译的sql:   //参数使用?作为占位符
             4.步骤         
                 1.导入驱动jar包
                 2.注册驱动
                 3.获取数据库对象 Connection
                 4.定义sql
                 		注意:// sql的参数使用?作为占位符,如 select * from user where username = ? and password = ?
			    5.获取执行sql语句的对象 PreParedStatement  Connection.preparStatement(String sql)
                 6.给 ? 赋值:
                 		方法:setXXX(参数1,参数2)
                 			参数1:?的编号从1开始
                 			参数2:?的值
                 7.执行sql ,接受返回的结果,不需要传递sql语句
                 8.处理结果
                 9.释放资源
             5.注意:后期都会使用 PreParedStatement 来完成增删改查的所有操作,放弃使用statement,防止出现sql注入
                 

2、2 抽取JDBC工具类( JDBCUtils)

​ 目的:简化书写

分析:

  1. 注册驱动抽取

  2. 抽取一个方法获取连接对象

  3. 抽取方法释放资源

    ​ 需求:不想传参(麻烦),还得保证工具类的通用性

    ​ 解决:配置文件

    ​ jdbc.properties

    ​ url =

    ​ user =

    ​ password =

    //工具类
    package club.suhai.Util;
    
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    import java.net.URL;
    import java.sql.*;
    import java.util.Properties;
    
    /**
     * jdbc工具类
     */
    public class JdbcUtils {
        private static String url;
        private static String user;
        private static String password;
        private static String driver;
        /**
         * 文件的读取,只需要读取一次即可拿到这些值,使用静态代码块
         */
        static {
            //读取资源文件
            //1.创建Properties对象
            Properties properties = new Properties();
            //加载文件
                //获取src路径下的文件的方式:---> ClassLoader 类加载器
            ClassLoader classLoader = JdbcUtils.class.getClassLoader();
            URL res = classLoader.getResource("jdbc.properties");
            String path = res.getPath();
            System.out.println(path);
            try {
                properties.load(new FileReader(path));
            } catch (IOException e) {
                e.printStackTrace();
            }
            //3.获取数据,赋值
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            driver = properties.getProperty("driver");
            try {
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * 获取连接方法
         * @return连接对象
         */
        public static Connection getConnection() throws SQLException{
            return DriverManager.getConnection(url,user,password);
        }
    
        /**
         * 释放资源
         * @param resultSet
         * @param statement
         * @param connection
         */
        public static void close(ResultSet resultSet,Statement statement, Connection connection){
            if (statement!=null){
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (connection!=null){
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
    
    

    //配置文件
    url = jdbc:mysql:///db1
    user = root
    password = 0610
    driver = com.mysql.jdbc.Driver
    
    //测试类
    package club.suhai.jdbc_demo;
    
    import club.suhai.Util.JdbcUtils;
    import club.suhai.domain.Emp;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class jdbcDemo7 {
        public static void main(String[] args) {
            //
            List<Emp> list = new jdbcDemo6().findAll();
            System.out.println(list);
            System.out.println(list.size());
        }
        /**
         * 演示工具类
         */
        public List<Emp> findAll(){
            ResultSet resultSet = null;
            Statement statement = null;
            Connection connection = null;
            List<Emp> list = null;
            //1.注册驱动
            try {
                Class.forName("com.mysql.jdbc.Driver");
                //2.获取连接
                try {
    //                connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8","root","0610");
                    connection = JdbcUtils.getConnection();
                    //3.定义sql
                    String sql = "select* from users";
                    //4.获取执行sql的对象
                    statement = connection.createStatement();
                    //5。执行sql
                    resultSet = statement.executeQuery(sql);
                    //6.遍历结果集
                    Emp emp = null;
                    //建立集合
                    list = new ArrayList<>();
                    while (resultSet.next()){
                        int id = resultSet.getInt("id");
                        String name = resultSet.getString("name");
                        Date birthday = resultSet.getDate("birthday");
                        String phone = resultSet.getString("phone");
                        //创建对象
                        emp = new Emp();
                        emp.setId(id);
                        emp.setName(name);
                        emp.setBirthday(birthday);
                        emp.setPhone(phone);
                        list.add(emp);
                    }
                    return list;
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }finally{
                JdbcUtils.close(resultSet,statement,connection);
            }
            return list;
        }
    }
    
    

练习:

​ 需求:

​ 1.通过键盘录入用户名密码

​ 2.判断用户是否登录成功

步骤:

​ 1.创建用户数据表

create table user(
	id int primary key auto_increm,
	username varchar(32),
	password varchar(32)
);

3、JDBC控制事务

  1. ​ 事务:一个包含多个步骤的业务操作,如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败

  2. ​ 操作:

    1. 开启事务
    2. 提交事务
    3. 回滚事务
  3. 使用connection对象来管理事务

    1. 开启事务:setAutoCommit(booleam autoCommit): 调用该方法设置参数为 false,即开启事务

      ​ 在执行sql前开启事务

    2. 提交事务:commit();

      当所有sql执行完,提交事务

    3. 回滚事务:rollback();

      在catch中回滚事务

4、JDBC连接池

4、1 数据库连接池

​ 1.概念:其实就是一个容器(集合),存放数据库连接的容器.

当系统初始化好后,容器被创建,容器中会申请一些数据库连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完后,会将连接对象归还给容器。

​ 2.好处:

				1.节约资源

				2.用户访问高效

​ 3.实现:

		标准接口 :DataSource    java.sql 包下的

					方法:  获取连接:getConnection()

						   归还连接:如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接,而是归还连接。

					一般我们不去实现它,有数据库厂商来实现

							1.  CP30:  数据库连接池技术(有点古老)

							2.  Druid: 数据库连接池技术,由阿里巴巴提供

4、2 C3P0

步骤:
    1.导入jar包,c3p0-0.9.5.2.jar和mchange-commons-java-0.2.12.jar  别忘记导入数据库驱动jar包 mysql-connector-java-5.1.37-bin.jar
    2.定义配置文件:
    	文件:c3p0.properties 或者 c3p0-config.xml
    	路径:直接将文件放在src目录下即可
   	3.创建核心对象 数据库连接池对象 ComboPooleDataSource
    4.获取连接: getC
package club.suhai.c3po;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * c3p0演示2
 */
public class c3p0Demo2 {
  public static void main(String[] args) throws SQLException {
    //1.获取DataSource ,使用默认配置
      DataSource dataSource = new ComboPooledDataSource();
//    <!--  超出最大连接数量(10)  -->
      for (int i = 1;i <= 11;i++ ) {
          Connection connection = dataSource.getConnection();
          System.out.println(i+":"+connection);
          if (i==5){
              connection.close(); //归还连接到连接池中
          }
      }
  }
  public void testNamedConfig() throws SQLException{
      DataSource dataSource = new ComboPooledDataSource("otherc3p0");
      for (int i = 1;i <= 11;i++ ) {
          Connection connection = dataSource.getConnection();
          System.out.println(i+":"+connection);
          if (i==5){
              connection.close(); //归还连接到连接池中
          }
      }
  }
}

4、2 Druid

1、步骤:
	1.导入jar包 druid-1.0.9.jar
	2.定义配置文件:
		是properties形式的
		可以叫任意名称,可以放在任意目录下
	3.获取数据库连接对象:通过工厂类来获取,DruidDataSourceFactory
	4.获取连接:getConnection;

2、定义工具类
	1.定义一个工具类DruidUtils
	
	2.提供静态代码块加载配置文件
	3.提供方法
		1.获取连接方法:通过数据库连接池获取连接
		2.释放资源
		3.获取连接池的方法
	
//propterties 配置文件
driverClassName = com.mysql.jdbc.Driver
#?设置字符集
url = jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8
username = root
password = 0610

#初始化连接数量
initialSize = 5
#最大连接数量
maxActive = 10
#最大等待时间
maxWait = 3000
package club.suhai.Druid;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * Druid演示
 */
public class DruidDemo {
  public static void main(String[] args) throws Exception{
    //
      Properties pro = new Properties();
      InputStream resourceAsStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
      pro.load(resourceAsStream);
      DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);
      Connection connection = dataSource.getConnection();
      System.out.println(connection);
  }
}
//提取工具类
package club.suhai.DruidUtils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
 * Druid工具类
 */
public class DruidUtils {
    //定义成员变量
    private static DataSource ds;

    static {
        try {
            //1.加载配置文件
            Properties pro = new Properties();
            pro.load(DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            //获取Datasource
                ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    /**
     * 释放资源
     */
    public static void close(PreparedStatement preparedStatement, Connection connection){
        close(null,preparedStatement,connection);
    }
    /**
     * 释放资源
     */
    public static void close(ResultSet resultSet,PreparedStatement preparedStatement, Connection connection){
        if (preparedStatement!=null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();//归还连接
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 获取连接池方法
     * @return
     */
    public static DataSource getDatasource(){
        return ds;
    }

}
package club.suhai.Druid;

import club.suhai.DruidUtils.DruidUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
//测试工具类
public class DruidTestUtils {
  public static void main(String[] args) {
    //给数据库表中添加数据
      Connection connection = null;
      PreparedStatement preparedStatement = null;
      //1.获取连接
      try {
          connection = DruidUtils.getConnection();
          //2.定义sql
          String sql = "insert into stu values(null,?,?)";
          //3.获取PreparesStatement
          preparedStatement = connection.prepareStatement(sql);
          //4.给sql赋值
          preparedStatement.setString(1,"丁六");
          preparedStatement.setDouble(2,999.00);
          int i = preparedStatement.executeUpdate(); //表示影响行数,判断是否执行成功
          System.out.println(i);
      } catch (SQLException throwables) {
          throwables.printStackTrace();
      }finally{
          DruidUtils.close(preparedStatement,connection);
      }
  }
}

5、JDBC Template

5、1 Spring JDBC

	Spring JDBC 的简单封装,提供了一个JDBC Template 对象简化JDBC开发
	步骤:
		1.导入jar包
		2.创建JDBCTemplate对象,依赖于数据源DataSource
			JDBCTemplate template = new JDBCTemplate(ds);
		3.调用JDBCTemplate方法来完成CRUD(增删改查)操作
			update(): 执行DML语句,增删改语句
			queryForMap(): 查询结果将结果集封装为Map集合
            	注意:Map结果集长度只能为1
			queryForList():查询结果将结果集封装为List集合
            	注意:它是将每一条记录封装为一个一个Map集合,再把Map集合装载到List集合里面
			query():查询结果,将结果集封装为 JavaBean 对象
            	query的参数:RowMapper
            		一般我们使用BeanProPertyRowMapper实现类 ,可以完成数据到JavaBean的自动封装
            		template.query(sql, new BeanPropertyRowMapper<类型>(类型.class));
			queryForObject(): 查询结果,将结果集封装为对象
		4.练习:
            需求:
            1.修改 1 号数据的account 为 10000.00
            2.添加一条记录
            3.删除刚才添加的记录
            4.查询id = 1 的记录,将其封装为Map集合
            	注意:Map结果集长度只能为1
            5.查询所有记录,将其封装为List
            	注意:它是将每一条记录封装为一个一个Map集合,再把Map集合装载到List集合里面
            6.查询所有记录,将其封装为Emp对象的List集合
            7.查询总的记录数
package club.suhai.JdbcTemplate;

import club.suhai.DruidUtils.DruidUtils;
import club.suhai.domain.Emp;
import club.suhai.domain.Emp2;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class JdbcTemplateDemo2 {
  //Junit单元测试 可以如方法独立执行

    //放在成员变量位置,不用重复书写,私有化,不让别的类引用
   private JdbcTemplate template = new JdbcTemplate(DruidUtils.getDatasource());
    /**
     *   1.修改 1 号数据的account 为 10000.00
     */
    @Test
    public void test1(){
        String sql = "update users set account = 5000.00 where id = ?";
        int count = template.update(sql,1);
        System.out.println(count);
    }

    /**
     * 2.添加一条记录
     */
    @Test
    public void test2(){
        String sql = "insert into users (id,name,account,phone) values (?,?,?,?)";
        int count = template.update(sql,6, "丁流",1000.00, "1111");
        System.out.println(count);
    }

    /**
     * 3.删除刚才添加的记录
     */
    @Test
    public void test3(){
        String sql = "delete from users where id = ?";
        int count = template.update(sql,6);
        System.out.println(count);
    }

    /**
     * 4.查询id = 1 的记录,将其封装为Map集合
     */
    @Test
    public void test4(){
        String sql = "select *from users where id = ?";
        Map<String,Object> map = template.queryForMap(sql,1);
        System.out.println(map);
    }

    /**
     * 5.查询所有记录,将其封装为List
     */
    @Test
    public void test5(){
        String sql = "select *from users";
        List<Map<String, Object>> list = template.queryForList(sql);
        System.out.println(list);
    }

    /**
     * 6.查询所有记录,将其封装为Emp对象的List集合
     */
    @Test
    public void test6(){
        String sql = "select *from users";
        List<Emp2> list = template.query(sql, new RowMapper<Emp2>() {
            @Override
            public Emp2 mapRow(ResultSet resultSet, int i) throws SQLException {
                Emp2 emp2 = new Emp2();
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                double account = resultSet.getDouble("account");
                String phone = resultSet.getString("phone");

                emp2.setId(id);
                emp2.setName(name);
                emp2.setAccount(account);
                emp2.setPhone(phone);
                return emp2;
            }
        });

        for (Emp2 emp : list) {
            System.out.println(emp);
        }
    }

    /**
     *  7.查询总的记录数
     */
    @Test
    public void test7(){
        String sql = "select *from users";
        List<Emp2> list = template.query(sql, new BeanPropertyRowMapper<Emp2>(Emp2.class));
        for (Emp2 emp :list ) {
            System.out.println(emp);
        }
    }
}
上一篇:5.表关系设计、范式、JDBC


下一篇:第一个JDBC程序