JAVA JDBC

JDBC


JDBC概述

JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库! 每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。

概念:Java语言操作数据库

本质:官网定义的一套操作所有关系型数据库的规则(接口)。各个数据库厂商来实现这套接口,提供数据库驱动包(jar包)。我们使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类


导入mysql驱动包

 

 

 

 


 开发步骤

  1.注册驱动:告知JVM使用的是哪一个数据库的驱动

  2.获得连接:使用JDBC中的类,完成对MySQL数据库的连接

  3.获得语句执行平台:通过连接对象获取对SQL语句的执行者对象

  4.执行sql语句:使用执行者对象,向数据库执行SQL语句  获取到数据库的执行后的结果

  5.处理结果

  6.释放资源:调用一堆close()方法.

public static void main(String[] args) throws SQLException, ClassNotFoundException {
        //注册驱动
        Class.forName("com.mysql.jdbc.Driver");
     //获得连接
        String url = "jdbc:mysql://localhost:3306/study";
        String username = "wdnmd";
        String password = "123";
        Connection connection = DriverManager.getConnection(url, username, password);
     //获得语句执行平台
        Statement statement = connection.createStatement();
     //执行sql语句
        String sql = "select * from sort";
     //处理结果 ResultSet resultSet
= statement.executeQuery(sql); while (resultSet.next()){ int sid = resultSet.getInt("sid"); String sname = resultSet.getString("sname"); double sprice = resultSet.getDouble("sprice"); String sdesc = resultSet.getString("sdesc"); System.out.println(sid +"-"+sname +"-"+ sprice +"-"+ sdesc); }      //释放资源 resultSet.close(); statement.close(); connection.close(); }

 查询用executeQuery 增删改用executeUpdate

JDBC规范定义驱动接口:java.sql.Driver,MySql驱动包提供了实现类:com.mysql.jdbc.Driver
DriverManager工具类,提供注册驱动的方法 registerDriver(),方法的参数是java.sql.Driver,所以我们可以通过如下语句进行注册:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
以上代码不推荐使用,存在两方面不足
1.    硬编码,后期不易于程序扩展和维护
2.    驱动被注册两次。
通常开发我们使用Class.forName() 加载一个使用字符串描述的驱动类。
如果使用Class.forName()将类加载到内存,该类的静态代码将自动执行。
通过查询com.mysql.jdbc.Driver源码,我们发现Driver类“主动”将自己进行注册
JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。
  第一部分是jdbc,这是固定的;
  第二部分是数据库名称,那么连接mysql数据库,第二部分当然是mysql了;
  第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及DATABASE名称(mydb)组成。
ResultSet实际上就是一张二维的表格,我们可以调用其boolean next()方法指向某行记录,
当第一次调用next()方法时,便指向第一行记录的位置,这时就可以使用ResultSet提供的getXXX(int col)方法(与索引从0开始不同个,列从1开始)来获取指定列的数据:

 


详解各个对象

  DriverManager:驱动管理对象

    1.注册驱动:

       写代码用:Class.forName("com.mysql.jdbc.Driver");       注册与给定的驱动程序

       通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块

         static{

            try{

              java.sql.DriverManager.registerDriver(new Driver());

             }catch(SQLExceprion E){

               throw new RuntimeException("Can't register driver!");

             }

            }

          注意:mysql5 之后的驱动jar包可以省略注册驱动的步骤

    2.获取数据库连接

        url:指定连接的路径

        user:用户名

        password:密码

  

 

  Connection:数据库连接对象

    1.获取执行sql的对象

    2.管理事务:

      提交事务:

      开启事务: 

 

      回滚事务:

  

 

  Statement:执行sql的对象

        1.执行sql

 返回值:影响的行数,可以通过这个影响的行数判断DML 语句是否执行成功 返回值>0则成功,反之失败  

  

   

  ResultSet:结果集对象

   next() :游标向下移动一行

   getXXX(参数)获取数据 xxx 代表数据类型:


PreparedStatement

假设有登录案例SQL语句如下:

SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;

此时,当用户输入正确的账号与密码后,查询到了信息则让用户登录。但是当用户输入的账号为XXX 密码为:XXX’  OR ‘a’=’a时,则真正执行的代码变为:

SELECT * FROM 用户表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’  OR ’a’=’a’;

此时,上述查询语句时永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL注入问题。

为此,我们使用PreparedStatement来解决对应的问题。使用PreparedStatement预处理对象时,建议每条sql语句所有的实际参数,都使用逗号分隔。

 public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");

        String url = "jdbc:mysql://localhost:3306/study";
        String username = "wdnmd";
        String password = "123";

        Connection connection = DriverManager.getConnection(url,username,password);


        Scanner scanner = new Scanner(System.in);
        String user = scanner.nextLine();
        String pass = scanner.nextLine();
        String sql = "select * from users where username=? and password = ?";

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        preparedStatement.setObject(1,user);
        preparedStatement.setObject(2,pass);

        ResultSet resultSet = preparedStatement.executeQuery();

        while (resultSet.next()){
            System.out.println(resultSet.getString("username")+resultSet.getString("password"));
        }

        resultSet.close();
        preparedStatement.close();
        connection.close();

    }

 


JDBC工具类

import java.sql.*;

public class JDBCutil {
    private JDBCutil(){}
    private static Connection connection;

    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/study";
            String username = "wdnmd";
            String password = "123";
            connection = DriverManager.getConnection(url,username,password);
        } catch (Exception e) {
            throw  new RuntimeException(e +"链接失败");
        }
    }

    public static Connection getConnection(){
        return connection;
    }
    //释放资源
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet !=null){
            try{
                resultSet.close();
            }catch (SQLException e){
            }
        }
        if (statement !=null){
            try{
                statement.close();
            }catch (SQLException e){
            }
        }
        if (connection !=null){
            try{
                connection.close();
            }catch (SQLException e){
            }
        }
    }

    public static void close(Connection connection, Statement statement){

        if (statement !=null){
            try{
                statement.close();
            }catch (SQLException e){
            }
        }
        if (connection !=null){
            try{
                connection.close();
            }catch (SQLException e){
            }
        }

    }
}

测试:

public static void main(String[] args) throws SQLException {
        Connection connection = JDBCutil.getConnection();
        PreparedStatement pst = connection.prepareStatement("select sname from sort");

        ResultSet resultSet = pst.executeQuery();
        while(resultSet.next()){
            System.out.println(resultSet.getString("sname"));
        }
        JDBCutil.close(connection,pst,resultSet);
    }

 


JDBC控制事务

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

   如果你在修改数据的时候 第一个sql和第二个sql 中间有个异常的话 第一个sql 执行了 但是第二个sql 却没执行 事务就是解决这类问题的

public static void main(String[] args) {
       Connection connection = null;
        PreparedStatement preparedStatement1 = null;
        PreparedStatement preparedStatement2 = null;
        try {
            connection = JDBCUtils.getConnection();
            connection.setAutoCommit(false);  //调用方法参数这种false就开启事务
       
            String sql = "update account set balance = balance - ? where id =?";
            String sql2 = "update account set balance = balance + ? where id =?";

            preparedStatement1 = connection.prepareStatement(sql);
            preparedStatement2 = connection.prepareStatement(sql2);

            preparedStatement1.setInt(1,500);
            preparedStatement1.setInt(2,1);

            preparedStatement2.setInt(1,500);
            preparedStatement2.setInt(2,2);

            preparedStatement1.executeUpdate();

            int i =3/0;

            preparedStatement2.executeUpdate();

            connection.commit();//当所有sql执行完成后提交事务

        } catch (Exception e) {
            try {
                if (connection != null){
                    connection.rollback(); //回滚事务
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JDBCUtils.close(preparedStatement1,connection);
            JDBCUtils.close(preparedStatement2,null);
        }
    }

 


数据库连接池

  其实就是一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

  好处:节约资源、用户访问高效

 

实现:

1. 标准接口:DataSource javax.sql包下的 1. 方法:
获取连接:getConnection()
归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

2. 一般我们不去实现它,有数据库厂商来实现
1. C3P0:数据库连接池技术
2. Druid:数据库连接池实现技术,由阿里巴巴提供的

 

C3P0:数据库连接池技术

步骤:1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,不要忘记导入数据库驱动jar包

2. 定义配置文件:
名称: c3p0.properties 或者 c3p0-config.xml
路径:直接将文件放在src目录下即可。

3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
4. 获取连接: getConnection
代码:
//1.创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
//2. 获取连接对象
Connection conn = ds.getConnection();

Druid:数据库连接池实现技术,由阿里巴巴提供的

步骤:
1. 导入jar包 druid-1.0.9.jar
2. 定义配置文件:
是properties形式的
可以叫任意名称,可以放在任意目录下
3. 加载配置文件。Properties
4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
5. 获取连接:getConnection
代码:
//3.加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//5.获取连接
Connection conn = ds.getConnection();


Druid连接池工具类

//定义database
    private static DataSource dataSource;

    static {
        try {
            //加载properties配置
            Properties properties = new Properties();
            properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            //加载database
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    //释放资源
    public static void close(Statement statement,Connection connection){
        close(statement,connection);
    }
    public static void close(ResultSet resultSet,Statement statement,Connection connection){
        if (resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    //获取连接池方法
    public static DataSource getDataSource(){
        return dataSource;
    }

JdbcTemplate

Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
步骤:
1. 导入jar包
2. 创建JdbcTemplate对象。依赖于数据源DataSource
  JdbcTemplate template = new JdbcTemplate(ds);

3. 调用JdbcTemplate的方法来完成CRUD的操作
  update():执行DML语句。增、删、改语句


  queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
  注意:这个方法查询的结果集长度只能是1


  queryForList():查询结果将结果集封装为list集合
  注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中


  query():查询结果,将结果封装为JavaBean对象
  query的参数:RowMapper
   一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
  new BeanPropertyRowMapper<类型>(类型.class)


  queryForObject:查询结果,将结果封装为对象
  一般用于聚合函数的查询

 

posted on 2019-09-23 19:09  viper23333  阅读(151)  评论(0编辑  收藏  举报