实现Java的JDBC编程

写在前面

  • 当下的应用系统绝大多数离不开数据库,Java 程序访问数据库的基本方式是通过JDBC来实现。
  • JDBC 是一种用于 SQL 语句的java API,它由 java.sql.,javaX.sql. 包中的类和接口组成。

1.JDBC 工作原理

  • Java 语言访问数据库操作完全面向抽象接口编程。
  • 开发数据库应用不用限定在特定数据库厂商的API。
  • 程序的可移植性大大增强。
    在这里插入图片描述

2. JDBC 开发步骤

在这里插入图片描述

2.1 配置数据库驱动

  • 构建成功的 Maven 项目包含 src 文件夹、target 文件夹、pom.xml 文件三部分组成,要想在项目中使用 JDBC 编程,必须在 pom.xml 文件中配置以下依赖,不然会出现无法连接数据库的问题。
  • 以MySQL为例:
 <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>

https://search.maven.org/
可供大家查找想要的依赖jar 包的属性。

2.2 加载数据库驱动

  • 加载数据库驱动,作为JDBC 开发步骤的第一步,主要是通过反射机制来实现的,通过类名反射得到,会出现 ClassNotFoundException 异常处理。
//1.加载数据库驱动(MySQL)备注:5.1之后可以不明确加载驱动
Class.forName( "com.mysql.jdbc.Driver" );

2.3 建立数据库连接

  • 连接数据库采用的是 DriverManager 的静态方法 getConnection(url)来建立连接,返回Connection 对象,另一种是通过DataSource(数据源)对象获取。
  • url 必须按照相应的规范书写,jdbc:database://host:port/databaseName?p1=v1&p2=v2 ,对于MySQL 数据库而言,url 可表示为 jdbc:mysql://localhost:3306/databaseName?user=root&password=123456 。
//2.连接数据库
            //jdbc:database://host:port/databaseName?p1=v1&p2=v2
            //jdbc:mysql://localhost:3306/student_management
            Connection connection =
                    DriverManager.getConnection( "jdbc:mysql://localhost:3306/studentdatabase?user=root&password=123456&useSSL=false" );

2.4 创建操作命令

  • <1> Statement 用于执行不带参数的简单SQL语句
//3.创建 Statement 命令
 Statement statement = connection.createStatement();

这种情况下创建的操作命令执行带参数的SQL语句会发生SQL注入。

  • <2> PreparedStatement 用于执行带或者不带参数的SQL语句
    此种情况下创建的操作命令有如下优点:
    性能比Statement高、SQL预编译、阻止常见的SQL注入攻击。
    需要注意的是PreparedStatement 的占位符:? 下标从1开始,并且不能使用多值。
//通过调用方法传入参数执行SQL语句
 public static void queryMemoGroupByName(String groupName) {
 	String sql = "select * from 表名 where 字段 in (?)";
    PreparedStatement preparedStatement = connection.prepareStatement( sql );
    preparedStatement.setString( 1, groupName );
 }

2.5 执行SQL语句

  • Statement 和 PreparedStatement
    对于 R 操作,statement 调用 executeQuery() 方法返回ResultSet 结果集;对于 CUD 操作statement 调用 executeUpdate() 方法返回 int 型,成功返回1,失败返回0。
//4.准备SQl语句执行SQL语句
//R 查询
  ResultSet resultSet = statement.executeQuery( "select *  from 表名" );
  ResultSet resultSet = preparedStatement.executeQuery();
//CUD 更新 删除 增加操作
  int insertValue =statement.executeUpdate("insert into 表名 values (  )" );
  int insertValue =preparedStatement.executeUpdate("insert into 表名 values (  )" );

2.6 处理返回结果集

  • ResultSet对象它被称为结果集,它代表符合SQL语句条件的所有行,并且它通过一套getXXX方法提供了对这些行中数据的访问。
  • ResultSet里的数据一行一行排列,每行有多个字段,并且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得到ResultSet里的所有记录,就应该使用while循环。
  while (resultSet.next()) {//如果返回true表示有下一行记录,则否无记录
	  int id = resultSet.getInt("id");
      String name = resultSet.getString("name");
      LocalDateTime createdTime = resultSet.getTimestamp("created_time").toLocalDateTime();
      LocalDateTime modifyTime = resultSet.getTimestamp("modify_time").toLocalDateTime();
      System.out.println(String.format("编号:%d, 名称:%s, 创建时间:%s, 修改时间:%s",
                                id, name,createdTime.toString(), modifyTime.toString()
                        ));
            }

2.7 关闭操作

  • 访问数据库完毕后必须关闭结果集、关闭命令、关闭连接三步操作,当然也可以使用try 自动关闭机制,因为 ResultSet Statement Connection 都已经实现了AutoCloseable接口。
//关闭结果集 关闭命令 关闭连接
  resultSet.close();
  statement.close();
  connection.close();
//AutoCloseable接口 自动关闭
 try(
	 Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/databaseName?user=root&password=123456&useSSL=false" );
             //3.创建命令
             Statement statement = connection.createStatement();
             //4.准备SQl语句
             ResultSet resultSet = statement.executeQuery( "select *  from 表名" )
        ) 

3. 典型代码

  • <1>Statement 引起SQL注入问题
import java.sql.*;

/**
 * @Auther: SolarL
 * @Date: 2018/11/24
 * @Description: com.sunlong.jdbc
 * @version: 1.0
 */
public class TestJDBC3 {

    public static void queryMemoGroupByName(String groupName) {
        try {
            Class.forName( "com.mysql.jdbc.Driver" );
            Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/studentdatabase?user=root&password=123456" );
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery( "select * from student_management where 学号 = '" + groupName + "'" );
               while (resultSet.next()) {
                String num = resultSet.getString( "学号" );
                String name = resultSet.getString( "姓名" );
                String sex = resultSet.getString( "性别" );
                String school = resultSet.getString( "学院" );
                String class1 = resultSet.getString( "班级" );
                String class2 = resultSet.getString( "籍贯" );

                System.out.println( String.format(
                        "学号:%s,姓名:%s,性别:%s,学院:%s,班级:%s,籍贯:%s",
                        num, name, sex, school, class1, class2
                ) );
            }

            resultSet.close();
            statement.close();
            connection.close();
        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        // queryMemoGroupByName( "201612345678" );
        //SQL注入
        //select * from student_management where 学号 = '+ groupName+';
        //select * from student_management where 学号= 'PHP组' or 1=1 or 1='';
        queryMemoGroupByName( "学生组' or 1=1 or 1='" );
    }
}

对于以上SQL注入问题的解决办法,只需要将创建操作命令的时候使用 PreparedStatement 创建即可。

  • <2> JDBC 开发模板
import java.sql.*;

/**
 * @Auther: SolarL
 * @Date: 2018/11/25
 * @Description: com.sunlong.jdbc
 * @version: 1.0
 */
public abstract class JdbcTemplate {
    private String url;
    private Connection connection;
    private Statement statement;
    private ResultSet resultSet;
    Integer effect = -1;

    //jdbc:mysql://localhost:3306/database?user=root&password=018162
    public JdbcTemplate(String host, Integer port, String databaseName, String user, String password) {
        this.url = String.format( "jdbc:mysql://%s:%d/%s?user=%s&password=%s", host, port, databaseName, user, password );

    }

    public final void call() {
        //1.加载驱动
        loadDriver();
        //2.创建连接
        createConnect();
        //3.创建命令
        createStatement();
        //4.准备SQL
        createSql();
        //5.执行SQL
        execute();
        //6.处理结果
        //第一类:CUD int 第二: R result
        handlerResult();
        //7.关闭结果集 关闭命令 关闭连接
        closeAll();
    }

    private void closeAll() {
        if (this.resultSet != null) {
            try {
                this.resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

        if (this.connection != null) {
            try {
                this.connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        this.effect = -1;

    }

    private void handlerResult() {
        if (this.executeType()) {
            try {
                this.handlerR( resultSet );
            } catch (SQLException e) {
                e.printStackTrace();
            }

        } else {
            this.handleCUD( effect );
        }
    }

    protected abstract void handleCUD(Integer effect);

    protected abstract void handlerR(ResultSet resultSet) throws SQLException;

    private void execute() {
        String sql = this.createSql();
        if (sql != null) {
            if (this.executeType()) {
                try {
                    resultSet = statement.executeQuery( sql );
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            } else {
                try {
                    effect = statement.executeUpdate( sql );
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    //如果返回true 查询, 如果返回false 插入,删除,更新
    public abstract boolean executeType();
    //用户来覆写
    public abstract String createSql();

    private void createStatement() {
        try {
            statement = connection.createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void createConnect() {
        try {
            connection = DriverManager.getConnection( this.url );
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void loadDriver() {
        try {
            Class.forName( "com.mysql.jdbc.Driver" );
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}



import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;

/**
 * @Auther: SolarL
 * @Date: 2018/11/26
 * @Description: com.sunlong.jdbc
 * @version: 1.0
 */
public class TestJdbcTemplate {
    public static void main(String[] args) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate( "localhost", 3306, "memo", "root", "123456" ) {
            @Override
            protected void handleCUD(Integer effect) {
                //do something
            }

            @Override
            protected void handlerR(ResultSet resultSet) throws SQLException {
                if (resultSet != null) {
                    while (resultSet.next()) {
                        int id = resultSet.getInt( "id" );
                        String name = resultSet.getString( "name" );
                        LocalDateTime createdTime = resultSet.getTimestamp( "created_time" ).toLocalDateTime();
                        LocalDateTime modifyTime = resultSet.getTimestamp( "modify_time" ).toLocalDateTime();
                        System.out.println(
                                String.format(
                                        "编号:%d, 名称:%s, 创建时间:%s, 修改时间:%s",
                                        id, name,
                                        createdTime.toString(),
                                        modifyTime.toString()
                                ) );
                    }
                }
            }

            @Override
            public boolean executeType() {
                return true;
            }

            @Override
            public String createSql() {
                return "select id,name,created_time,modify_time from memo_group ";
            }
        };

        jdbcTemplate.call();
    }
}
  • <3> JDBC 事务管理
  • 数据库中,如不进行手动设置,事务默认自动提交,当我们在进行更新操作正常的情况下,进行错误插入,如果事务自动提交,则会发生事务的不一致性,当我们手动设置事务提交,待操作完全完成后提交事务,出现错误回滚的原始操作,就可确保事务的一致性。
import java.sql.*;

/**
 * @Auther: SolarL
 * @Date: 2018/11/25
 * @Description: com.sunlong.jdbc
 * @version: 1.0
 */
public class TransactionJdbc {
    public static void main(String[] args) {
        //演示事务
        //1.更新操作 - 正常
        //2.插入操作 - 错误
        transaction();
    }

    public static void transaction() {
        Connection connection = null;
        try {
            //1、加载数据库驱动
            Class.forName( "com.mysql.jdbc.Driver" );
            //2.建立连接,连接数据库
            //关于数据库连接的URL格式JDBC规范里面也有定义
            // jdbc:database://host:port/databaseName?p1=v1&p2=v2
            //jdbc:mysql://localhost:3306/memo?user=root&password=123456
            connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/studentdatabase?user=root&password=018162" );
            connection.setAutoCommit( false );
            //3.创建命令
            String updateSQL = " update student_management set 班级 = ? where 学号 = ?";
            PreparedStatement preparedStatement = connection.prepareStatement( updateSQL );
            preparedStatement.setString( 1, "信息163" );
            preparedStatement.setString( 2, "201611010321" );

            //4.准备SQL并执行
            int effectUpdate = preparedStatement.executeUpdate();
            System.out.println( "更新操作" + (effectUpdate == 1) );

            String insertSQL = "insert into student_management(id,name) values (?,?)";
            preparedStatement = connection.prepareStatement( insertSQL );
            int effectInsert = preparedStatement.executeUpdate();
            System.out.println( "插入操作:" + (effectInsert == 1) );
            
            if (effectUpdate == 1 && effectInsert == 1) {
                connection.commit();
            } else {
                connection.rollback();
            }

            //7.关闭命令
            preparedStatement.close();
            //8.关闭连接
            connection.close();

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
            if (connection != null) {
                try {
                    connection.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
}

结束语

小哥哥,小姐姐们,长得这么好看的你,觉得文章还不错就关注我吧,顺便给我点个赞鼓励一下我吧,哈哈哈
在这里插入图片描述

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值