三十七、Java基础之JDBC

一、Java代码使用JDBC之Statement

1.六个步骤:

/**
 * JDBC驱动六大步骤:
 * 1、注册数据库驱动,目的是为了让jvm可以识别mysql数据库驱动类
 * 2、获取和数据库的连接对象
 * 3、通过连接获取语句对象
 * 4、通过语句对象执行具体的DQL语句对象,返回结果集对象
 * 5、遍历结果集,取出每条记录
 * 6、关闭数据库相 关资源
 */

2.用到的方法:

//1、注册数据库驱动:
Driver driver = new com.mysql.jdbc.Driver();
 //通过驱动管理器注册驱动
DriverManager.registerDriver(driver);
//2、获取和数据库的连接
//a、准备数据库相关资源
String username="root";
String password = "123456";
String url="jdbc:mysql://localhost:3306/test-csj";
//b、获取和数据库的连接
conn = DriverManager.getConnection(url, username, password);
//3、通过连接获取语句对象
//Statement是jdbc定一个的接口,表示sql语句
//conn.createStatement():返回的是一个具体类对象,这个具体类实现了Statement 接口
state = conn.createStatement();
//4、通过语句对象执行具体的DQL语句对象,返回结果集对象
//a、准备好sql语句
 //b、sql有不同的种类,Statement表示不同的sql语句,所以Statement上面有不同的方法执行不同的sql语句
 //我们通过调用Statement上面的executeQuery(sql)执行DQL语句,数据库返回结果集对象,
String sql = "SELECT * FROM user_info WHERE role_id=2;";

ResultSet res = state.executeQuery(sql);
//5、遍历结果集,取出每条记录

if (state.execute(sql)){
                res = state.getResultSet();
                //5、遍历结果集,取出每条记录
                while(res.next()){
                    //res.next():a、判断结果集中是否有下一条数据,b、如果有下一行,迭代器移动到下一行

                    //通过字段在查询列表中位置取得字段信息,位置从1开始
                    String name1 = res.getString(2);
                    //通过该字段名称取得字段信息,这是首选方式,;字段名称不区分大小写
                    String name2 = res.getString("name");
                    int id1 = res.getInt(1);
                    int id2 = res.getInt("id");
                    Date create_time = res.getDate("create_time");
                    String account = res.getString("account");
                    String employee_number = res.getString("employee_number");
                    String email = res.getString("email");
                    System.out.println(id2+" ,"+name2+" ,"+account+" ,"+email+" ,"+employee_number+" ,"+create_time+" .");
                }
            }
 //6、关闭数据库相关资源
            //在关闭的时候,需要反向关闭
            //异常处理:
            //          a、可以合着处理,也就是一个try处理多个异常,后面也可接多个catch
            //          b、可以分着处理,也就是分别用try....catch....处理每个异常
            //          c、何时分着?何时合着?当多个操作之间有联系的时候,应该合着处理;没有联系的时候,分着处理
            if (res!=null) {
                try {
                    res.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

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

3.实例

public class Test01 {

    public  static void main(String[] args){
        test01();
        test02();
    }

    private static void test02() {

        //1、注册数据库驱动,目的是为了让jvm可以识别mysql数据库驱动类
        //com.mysql.jdbc.Driver()是SUN公司对Driver接口的实现类型
        Connection conn=null;
        Statement state=null;
        ResultSet res=null;

        try {
            Driver driver = new com.mysql.jdbc.Driver();
            //通过驱动管理器注册驱动
            DriverManager.registerDriver(driver);

            //2、获取和数据库的连接
            //a、准备数据库相关资源
            String username="root";
            String password = "123456";

            //url:统一资源定位器,确定数据库服务器的信息
            //jdbc:是一套网络协议,jdbc:mysql:是jdbc协议下的mysql协议
            String url="jdbc:mysql://localhost:3306/test-csj";
            //b、获取和数据库的连接
            //Connection是jdbc定义的接口,表示和数据库的连接
            //DriverManager.getConnection返回的是一个具体类对象,这个具体类实现了Connection接口
            //这个具体类在驱动的jar文件中,
            conn = DriverManager.getConnection(url, username, password);
            //3、通过连接获取语句对象
            //Statement是jdbc定一个的接口,表示sql语句
            //conn.createStatement():返回的是一个具体类对象,这个具体类实现了Statement 接口
            state = conn.createStatement();
            //4、通过语句对象执行具体的DQL语句对象,返回结果集对象
            //a、准别好sql语句
            //b、sql有不同的种类,Statement表示不同的sql语句,所以Statement上面有不同的方法执行不同的sql语句
            //我们通过调用Statement上面的executeQuery(sql)执行DQL语句,数据库返回结果集对象,
            String sql = "SELECT * FROM user_info WHERE role_id=2;";
            String sql2= "INSERT INTO user_info VALUES(666,'chuchu','chuchu');";
            //调用Statement中的getResultSet()方法获取,

            if (state.execute(sql)){
                res = state.getResultSet();
                //5、遍历结果集,取出每条记录
                while(res.next()){
                    //res.next():a、判断结果集中是否有下一条数据,b、如果有下一行,迭代器移动到下一行

                    //通过字段在查询列表中位置取得字段信息,位置从1开始
                    String name1 = res.getString(2);
                    //通过该字段名称取得字段信息,这是首选方式,;字段名称不区分大小写
                    String name2 = res.getString("name");
                    int id1 = res.getInt(1);
                    int id2 = res.getInt("id");
                    Date create_time = res.getDate("create_time");
                    String account = res.getString("account");
                    String employee_number = res.getString("employee_number");
                    String email = res.getString("email");
                    System.out.println(id2+" ,"+name2+" ,"+account+" ,"+email+" ,"+employee_number+" ,"+create_time+" .");
                }
            }
            if (!state.execute(sql2)){
                int i = state.executeUpdate(sql2);
                System.out.println("i="+i);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、关闭数据库相关资源
            //在关闭的时候,需要反向关闭
            //异常处理:
            //          a、可以合着处理,也就是一个try处理多个异常,后面也可接多个catch
            //          b、可以分着处理,也就是分别用try....catch....处理每个异常
            //          c、何时分着?何时合着?当多个操作之间有联系的时候,应该合着处理;没有联系的时候,分着处理
            if (res!=null) {
                try {
                    res.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

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

    private static void test01() {
        //1、注册数据库驱动,目的是为了让jvm可以识别mysql数据库驱动类
        //com.mysql.jdbc.Driver()是SUN公司对Driver接口的实现类型
        Connection conn=null;
        ResultSet res=null;
        Statement state=null;

        try {
            Driver driver = new com.mysql.jdbc.Driver();
            //通过驱动管理器注册驱动
            DriverManager.registerDriver(driver);

            //2、获取和数据库的连接
            //a、准备数据库相关资源
            String username="root";
            String password = "123456";

            //url:统一资源定位器,确定数据库服务器的信息
            //jdbc:是一套网络协议,jdbc:mysql:是jdbc协议下的mysql协议

            String url="jdbc:mysql://localhost:3306/test-csj";

            //b、获取和数据库的连接
            //Connection是jdbc定义的接口,表示和数据库的连接
            //DriverManager.getConnection返回的是一个具体类对象,这个具体类实现了Connection接口
            //这个具体类在驱动的jar文件中,
            conn = DriverManager.getConnection(url, username, password);

            //3、通过连接获取语句对象
            //Statement是jdbc定一个的接口,表示sql语句
            //conn.createStatement():返回的是一个具体类对象,这个具体类实现了Statement 接口
            state = conn.createStatement();

            //4、通过语句对象执行具体的DQL语句对象,返回结果集对象
            //a、准别好sql语句
            //b、sql有不同的种类,Statement表示不同的sql语句,所以Statement上面有不同的方法执行不同的sql语句
            //我们通过调用Statement上面的executeQuery(sql)执行DQL语句,数据库返回结果集对象,
            String sql = "SELECT * FROM user_info WHERE role_id=2;";
            res = state.executeQuery(sql);
            System.out.println(res);

            //5、遍历结果集,取出每条记录
            while(res.next()){
                //res.next():a、判断结果集中是否有下一条数据,b、如果有下一行,迭代器移动到下一行

                //通过字段在查询列表中位置取得字段信息,位置从1开始
                String name1 = res.getString(2);
                //通过该字段名称取得字段信息,这是首选方式,;字段名称不区分大小写
                String name2 = res.getString("name");

                int id1 = res.getInt(1);
                int id2 = res.getInt("id");

                Date create_time = res.getDate("create_time");

                String account = res.getString("account");

                String employee_number = res.getString("employee_number");
                String email = res.getString("email");
                System.out.println(id2+" ,"+name2+" ,"+account+" ,"+email+" ,"+employee_number+" ,"+create_time+" .");

            }





        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、关闭数据库相关资源
            //在关闭的时候,需要反向关闭
            //异常处理:
            //          a、可以合着处理,也就是一个try处理多个异常,后面也可接多个catch
            //          b、可以分着处理,也就是分别用try....catch....处理每个异常
            //          c、何时分着?何时合着?当多个操作之间有联系的时候,应该合着处理;没有联系的时候,分着处理
            if (res!=null) {
                try {
                    res.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

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

二、由于代码中重复的代码很多,故进行封装

1.新建uti l/jdbcUtil封装类(获取数据库连接对象,和关闭数据库)

a、db.properties(为了读取文件,我们需要获取InputStream,注意下面这种方式是专门用来读取src下的文件的)
user1 =root
password1=123456
url1=jdbc:mysql://localhost:3306/csjin
className1=com.mysql.jdbc.Driver

b、获取db.properties中的数据并通过流InputStream读取到代码中:

//为了读取文件,我们需要获取InputStream,注意下面这种方式是专门用来读取src下的文件的
//获取jdbcUtil类对应的Class对象
 Class<jdbcUtil> clasz = jdbcUtil.class;
 //通过Class对象获取ClassLoader类加载器对象
ClassLoader loader = clasz.getClassLoader();
//调用ClassLoader上面的方法获取inputStream
 InputStream in = loader.getResourceAsStream("db.properties");

 Properties pro = new Properties();

 //把pro对象和流连接起来
 pro.load(in);

user = pro.getProperty("user1");
password = pro.getProperty("password1");
url = pro.getProperty("url1");
className = pro.getProperty("className1");

c、封装获取数据库连接

/**
     * 注册驱动获取链接
     * @return
     */
    public static Connection getConnection() throws SQLException, ClassNotFoundException {

        Class.forName(className);//反射方法获取驱动
        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;

    }

其他方法获取数据库驱动:

//方式一:我们创建new com.mysql.jdbc.Driver类对象的时候,JVM把这个类加载到内存
//这样JVM就可以是被MySQL的数据库驱动了
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);

 //方式二:我们创建new com.mysql.jdbc.Driver类对象的时候,JVM把这个类加载到内存
//这样JVM就可以是被MySQL的数据库驱动了
 Driver driver = new com.mysql.jdbc.Driver();可以不用执行DriverManager.registerDriver(driver);

 //方式三:使用反射方法,我们获取com.mysql.jdbc.Driver这个类对应的class类的时候,
 //JVM需要把com.mysql.jdbc.Driver自动加载到内存,这个JVM就可以识别数据库驱动了

2.代码实例:

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class jdbcUtil {

    private static String user;
    private static String password;
    private static String url;
    private static String className;

    static {
       /* //为了读取文件,我们需要获取InputStream,注意下面这种方式是专门用来读取src下的文件的
        //获取jdbcUtil类对应的Class对象
        Class<jdbcUtil> clasz = jdbcUtil.class;
        //通过Class对象获取ClassLoader类加载器对象
        ClassLoader loader = clasz.getClassLoader();
        //调用ClassLoader上面的方法获取inputStream
        InputStream in = loader.getResourceAsStream("db.properties");*/

        /**并上面三行代码*/
        InputStream in = jdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
        //为了方便的读取"db.properties"这张特殊格式的文件,创建一个java.util.properties类对象
        Properties pro = new Properties();

        try {
            //把pro对象和流连接起来
            pro.load(in);

            user = pro.getProperty("user1");
            password = pro.getProperty("password1");
            url = pro.getProperty("url1");
            className = pro.getProperty("className1");
        }catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 注册驱动获取链接
     * @return
     */
    public static Connection getConnection() throws SQLException, ClassNotFoundException {

        Class.forName(className);
        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;

    }

    /**
     * 关闭数据库相关对象的方法
     */
    public static void closeDb(Connection conn, Statement state, ResultSet res){

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

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

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

3.调用封装的方法jdbcUtil,执行数据库sql

import com.csjin.edu.TestJDBC.Test02.util.jdbcUtil;

import java.sql.*;

public class Test02 {
    
    public static void main(String[] args) throws SQLException, ClassNotFoundException {

        /**
         * 方式一:我们创建new com.mysql.jdbc.Driver类对象的时候,JVM把这个类加载到内存
         * 这样JVM就可以是被MySQL的数据库驱动了
         *  Driver driver = new com.mysql.jdbc.Driver();
         * DriverManager.registerDriver(driver);
         */
       test1();
        /**
         * 方式一:我们创建new com.mysql.jdbc.Driver类对象的时候,JVM把这个类加载到内存
         * 这样JVM就可以是被MySQL的数据库驱动了
         *  Driver driver = new com.mysql.jdbc.Driver();可以不用执行DriverManager.registerDriver(driver);
         */
        test2();
        /**
         * 使用反射方法,我们获取com.mysql.jdbc.Driver这个类对应的class类的时候,
         * JVM需要把com.mysql.jdbc.Driver自动加载到内存,这个JVM就可以识别数据库驱动了
         */
       test3();

        test4();
    }

    private static void test4() {

        Connection conn=null;
        Statement state=null;
        ResultSet res=null;
        try {
            conn = jdbcUtil.getConnection();
            state = conn.createStatement();


            String sql = "SELECT * FROM user_info WHERE role_id=2;";
            String sql2= "INSERT INTO user_info VALUES(222,'李','chu01','4b31a1d73cea9e6c432b59adc9eed725',1,2,111111,NULL,NULL,NULL,'aaaa@qq.com',NULL,NULL,0,'2020-03-20 00:00:00','2017-11-30 10:21:01','2017-11-30 10:21:01',1);";

            //如果第一个结果为 ResultSet 对象,则返回 true;如果其为更新计数或者不存在任何结果,则返回false
            if (!state.execute(sql2)){
                //  来获取更新计数器
                int count = state.getUpdateCount();
                System.out.println("count ="+count);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                jdbcUtil.closeDb(conn,state,res);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }


    private static void test3() throws ClassNotFoundException, SQLException {

        String className = "com.mysql.jdbc.Driver";

        Class.forName(className);

        String username="root";
        String password = "123456";

        //url:统一资源定位器,确定数据库服务器的信息
        //jdbc:是一套网络协议,jdbc:mysql:是jdbc协议下的mysql协议
        String url="jdbc:mysql://localhost:3306/test-csj";
        Connection conn = DriverManager.getConnection(url, username, password);
        if (conn!=null){
            System.out.println("驱动注册成功3!");
        }
    }

    private static void test2() throws SQLException {
        Driver driver = new com.mysql.jdbc.Driver();
        //通过驱动管理器注册驱动
        String username="root";
        String password = "123456";

        //url:统一资源定位器,确定数据库服务器的信息
        //jdbc:是一套网络协议,jdbc:mysql:是jdbc协议下的mysql协议
        String url="jdbc:mysql://localhost:3306/test-csj";
        Connection conn = DriverManager.getConnection(url, username, password);
        if (conn!=null){
            System.out.println("驱动注册成功2!");
        }

    }

    private static void test1() throws SQLException {

        Driver driver = new com.mysql.jdbc.Driver();
        //通过驱动管理器注册驱动
        DriverManager.registerDriver(driver);
        String username="root";
        String password = "123456";

        //url:统一资源定位器,确定数据库服务器的信息
        //jdbc:是一套网络协议,jdbc:mysql:是jdbc协议下的mysql协议
        String url="jdbc:mysql://localhost:3306/test-csj";
        Connection conn = DriverManager.getConnection(url, username, password);
        if (conn!=null){
            System.out.println("驱动注册成功1!");
        }
    }
}

 三、如何防止SQl注入攻击

/**
 * sql注入攻击:
 * SELECT * FROM users WHERE username='sss' AND `password`='ss' or 'x' = 'x';
 *
 * 如何避免sql注入攻击:
 * 使用PreparedStatement,PreparedStatement不需要sql拼接
 *
 * 比较PreparedStatement与Statement区别?
 * 1、Statement执行sql语句的时候,编译一次,执行一次,执行效率低
 *    PreparedStatemen执行sql语句的时候,编译一次,可以反复执行,效率高
 * 2、Statement执行sql语句需要拼接,有sql注入风险
 *    PreparedStatemen执行sql语句不需要拼接,使用占位符即可,可 避免sql注入
 *
 */

1.从键盘获取用户名和密码,并将此方法封装成一个map类型的

public class Test03 {

    public static Map<String,String> readkeyBoard(){

        Map<String,String> map = new HashMap<>();

        Scanner scan = new Scanner(System.in);
        System.out.println("请输入username,并回车:");
        String user = scan.nextLine();//scan.nextLine();以
为标记读取一
        map.put("user",user);

        System.out.println("请输入password,并回车:");
        String password =  scan.nextLine();
        map.put("password",password);

        if (scan != null){
            scan.close();
        }

        return map;
    }

2.利用登陆实例说明SQL注入,无防止

密码只要输入:ss' or 'x' = 'x     即可登录成功,因为Statement,我们只能使用的sql拼接

/**
     * 检查登录是否成功
     * @return
     */
    public static boolean login(){

        Map<String,String> map = readkeyBoard();

        Connection conn =null;
        Statement state =null;
        ResultSet res = null;
        boolean flag = false;
        try {
            conn = jdbcUtil.getConnection();
            state = conn.createStatement();
            String sql = "SELECT * FROM users WHERE username='"+map.get("user")+"' AND `password`='"+map.get("password")+"';";
            System.out.println(sql);
            res = state.executeQuery(sql);
            System.out.println(res);
            /**
             * 查询结果中有数据
             */
            if (res.next()){
                flag=true;
            }


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

            jdbcUtil.closeDb(conn,state,res);
        }
        return flag;
    }
 public static void main(String[] args){
        if (login()){
            System.out.println("登录成功!");
        }else{
            System.out.println("无效的用户名密码");
        }
    }

3.防止使用SQL注入,使用PreparedStatement,不实用拼接SQL,使用?占位符

/**
     * 检查登录是否成功,防止SQL注入
     * @return
     */
    public static boolean loginSQL(){

        Map<String,String> map = readkeyBoard();

        Connection conn =null;
        PreparedStatement pstate =null;
        ResultSet res = null;
        boolean flag = false;

        try {
            conn = jdbcUtil.getConnection();

            //由于pstate对象需要把SQL预先编译到pstate对象中,所以我们需要提前准别一个SQL语句
            //注意:SQL语句中所有需要设置的内容,不论是什么类型,统统用一个占位符?表示,?表示需要设置的内容
            String sql = "SELECT * FROM users WHERE username =? AND password =? ";

            //把SQL语句编译到pstate对象中,并且返回pstate对象
            pstate = conn.prepareStatement(sql);
            //设置占位符具体值,注意从1开始
            pstate.setString(1,map.get("user"));
            pstate.setString(2,map.get("password"));

            //输出SQL语句
            System.out.println(sql);
            //由于SQL语句已经预先被预编译到pstate对象中,所以pstate.executeQuery()时候已经不需要SQL语句了
            res = pstate.executeQuery();
            System.out.println(res);
            /**
             * 查询结果中有数据
             */
            if (res.next()){
                flag=true;
            }
            //输出SQL语句
            System.out.println(sql);


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

            jdbcUtil.closeDb(conn,pstate,res);
        }
        return flag;
    }

    public static void main(String[] args){
        if (loginSQL()){
            System.out.println("登录成功!");
        }else{
            System.out.println("无效的用户名密码");
        }
    }
}

四、其他案例

import com.csjin.edu.TestJDBC.Test02.util.jdbcUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Test04 {

    public static void main(String[] args){

        //执行数据库DML
        test1();
        //执行数据DQL
        test2();

    }

    private static void test2() {
        Connection conn = null;
        PreparedStatement pstate = null;
        ResultSet res = null;

        try{

        conn = jdbcUtil.getConnection();

        String sql ="SELECT username,id,password FROM USERS where username=?";

        pstate = conn.prepareStatement(sql);
        pstate.setString(1,"admin");

        res = pstate.executeQuery();
        while (res.next()){
            String username = res.getString("username");
            int id = res.getInt("id");
            String password = res.getString("password");
            System.out.println("username ="+username+",id="+id+",password="+password);
        }


    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        jdbcUtil.closeDb(conn,pstate,res);
    }


}

    private static void test1() {

        Connection conn = null;
        PreparedStatement pstate = null;
        ResultSet res = null;

        try {
            conn = jdbcUtil.getConnection();

            String sql = "INSERT INTO USERS VALUES(?,?,?)";

            pstate = conn.prepareStatement(sql);
            pstate.setInt(1,2);
            pstate.setString(2,"chu01");
            pstate.setString(3,"123456");

            int i = pstate.executeUpdate();
            System.out.println("i="+i);

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            jdbcUtil.closeDb(conn,pstate,null);
        }
    }


}

五、使用PreparedStatement执行模糊查询

package com.csjin.edu.TestJDBC.Test02;

import com.csjin.edu.TestJDBC.Test02.util.jdbcUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 使用PreparedStatement执行模糊查询
 *
 */

public class Test05 {

    public static void main(String[] args){

        //使用PreparedStatement执行模糊查询
        test1();
    }

    private static void test1() {
        Connection conn = null;
        PreparedStatement pstate = null;
        ResultSet res = null;

        try{

            conn = jdbcUtil.getConnection();

            String sql ="SELECT username,id,password FROM USERS where username like ?";

            pstate = conn.prepareStatement(sql);
            pstate.setString(1,"%dmi%");

            res = pstate.executeQuery();
            while (res.next()){
                String username = res.getString("username");
                int id = res.getInt("id");
                String password = res.getString("password");
                System.out.println("username ="+username+",id="+id+",password="+password);
            }


        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            jdbcUtil.closeDb(conn,pstate,res);
        }
    }
}

六、数据库事务与JDBC事务

/**
 * 数据库事物
 * Mysql中默认的事物管理方式是自动提交事务,mysql默认每个DML语句都会引起一个单独的事务,这个DML语句执行结束的时候,事务会自动提交
 *
 * 在数据库需要自动关闭事务:
 * 1、执行语句START TRANSACTION ,自动关闭事务,注意:这是本次关闭,在事务结束后,会恢复到默认自动提交
 * 2、在事务开始后,只要没有结束事务,无论执行多少个DML语句,这些DML语句都是隶属于同一个事务,事务中对数据库修改保存在内存中
 * 3、事务结束的两种方式:
 *    1、提交(COMMIT),结束事务,事务中对数据库的修改被永久的保存到数据库中
 *    2、回滚(ROLLBACK)结束事务,事务中的对数据库的修改被放弃
 *
 *
 *
 *在JDBC需要自动关闭事务:
 * 1、执行语句conn.setAutoCommit(false); ,自动关闭事务,注意:这是本次关闭,在事务结束后,会恢复到默认自动提交
 * 2、在事务开始后,只要没有结束事务,无论执行多少个DML语句,这些DML语句都是隶属于同一个事务,事务中对数据库修改保存在内存中
 * 3、事务结束的两种方式:
 *    1、提交(conn.commit()),结束事务,事务中对数据库的修改被永久的保存到数据库中
 *    2、回滚(conn.rollback)结束事务,事务中的对数据库的修改被放弃
 *
 */
import com.csjin.edu.TestJDBC.Test02.util.jdbcUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 数据库事物
 * Mysql中默认的事物管理方式是自动提交事务,mysql默认每个DML语句都会引起一个单独的事务,这个DML语句执行结束的时候,事务会自动提交
 *
 * 在数据库需要自动关闭事务:
 * 1、执行语句START TRANSACTION ,自动关闭事务,注意:这是本次关闭,在事务结束后,会恢复到默认自动提交
 * 2、在事务开始后,只要没有结束事务,无论执行多少个DML语句,这些DML语句都是隶属于同一个事务,事务中对数据库修改保存在内存中
 * 3、事务结束的两种方式:
 *    1、提交(COMMIT),结束事务,事务中对数据库的修改被永久的保存到数据库中
 *    2、回滚(ROLLBACK)结束事务,事务中的对数据库的修改被放弃
 *
 *
 *
 *在JDBC需要自动关闭事务:
 * 1、执行语句conn.setAutoCommit(false); ,自动关闭事务,注意:这是本次关闭,在事务结束后,会恢复到默认自动提交
 * 2、在事务开始后,只要没有结束事务,无论执行多少个DML语句,这些DML语句都是隶属于同一个事务,事务中对数据库修改保存在内存中
 * 3、事务结束的两种方式:
 *    1、提交(conn.commit()),结束事务,事务中对数据库的修改被永久的保存到数据库中
 *    2、回滚(conn.rollback)结束事务,事务中的对数据库的修改被放弃
 *
 */
public class Test06 {

    public static void main(String[] args){

        //非事务
        test1();

        //事务成功
        test2();
        //事务过程中失败,需手动执行回滚操作
        test3();

    }

    private static void test3() {

        Connection conn = null;
        PreparedStatement pstate = null;
        ResultSet res = null;

        try {
            conn = jdbcUtil.getConnection();

            //开启事务,关闭自动提交
            conn.setAutoCommit(false);

            String sql = "INSERT INTO users VALUES(?,?,?)";

            pstate = conn.prepareStatement(sql);

            // 设置并执行第一个DML语句
            pstate.setInt(1,2);
            pstate.setString(2,"chu02");
            pstate.setString(3,"123456");

            int i = pstate.executeUpdate();
            System.out.println("i="+i);

            // 设置并执行第二个DML语句
            pstate.setInt(1,3);
            pstate.setString(2,"chu03");
            pstate.setString(3,"123456");

            i = pstate.executeUpdate();
            System.out.println("i="+i);


            // 设置并执行第三个DML语句
            pstate.setInt(1,1);
            pstate.setString(2,"chu04");
            pstate.setString(3,"12345611111111111111111111111111111111111111111111111111111111111111111111111");

            i = pstate.executeUpdate();
            System.out.println("i="+i);

            //提交事务
            conn.commit();

        } catch (SQLException e) {
            System.err.println("事务SQLException异常信息如下:");
            e.printStackTrace();
            //手动回滚
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            System.out.println("事务ClassNotFoundException异常信息如下:");
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            jdbcUtil.closeDb(conn,pstate,null);
        }
    }

    private static void test2() {

        Connection conn = null;
        PreparedStatement pstate = null;
        ResultSet res = null;

        try {
            conn = jdbcUtil.getConnection();

            //开启事务,关闭自动提交
            conn.setAutoCommit(false);

            String sql = "INSERT INTO users VALUES(?,?,?)";

            pstate = conn.prepareStatement(sql);

            // 设置并执行第一个DML语句
            pstate.setInt(1,2);
            pstate.setString(2,"chu02");
            pstate.setString(3,"123456");

            int i = pstate.executeUpdate();
            System.out.println("i="+i);

            // 设置并执行第二个DML语句
            pstate.setInt(1,3);
            pstate.setString(2,"chu03");
            pstate.setString(3,"123456");

            i = pstate.executeUpdate();
            System.out.println("i="+i);


            // 设置并执行第三个DML语句
            pstate.setInt(1,4);
            pstate.setString(2,"chu04");
            pstate.setString(3,"123456");

            i = pstate.executeUpdate();
            System.out.println("i="+i);

            //提交事务
            conn.commit();

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            jdbcUtil.closeDb(conn,pstate,null);
        }
    }

    private static void test1() {

        Connection conn = null;
        PreparedStatement pstate = null;
        ResultSet res = null;

        try {
            conn = jdbcUtil.getConnection();

            String sql = "INSERT INTO users VALUES(?,?,?)";

            pstate = conn.prepareStatement(sql);

            // 设置并执行第一个DML语句,并且自动提交
            pstate.setInt(1,2);
            pstate.setString(2,"chu02");
            pstate.setString(3,"123456");

            int i = pstate.executeUpdate();
            System.out.println("i="+i);

            // 设置并执行第二个DML语句,并且自动提交
            pstate.setInt(1,3);
            pstate.setString(2,"chu03");
            pstate.setString(3,"123456");

            i = pstate.executeUpdate();
            System.out.println("i="+i);


            // 设置并执行第三个DML语句,并且自动提交
            pstate.setInt(1,4);
            pstate.setString(2,"chu04");
            pstate.setString(3,"123456");

            i = pstate.executeUpdate();
            System.out.println("i="+i);

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            jdbcUtil.closeDb(conn,pstate,null);
        }

    }
}

七、在数据库与JDBC中使用行级锁

/**
 * 在数据库中使用行级锁:
 * 1、执行数据库语句:start transaction ,关闭数据库自动提交
 * 2、执行语句:select * from users where id in(1,2) for update; 引起事务,启动行级锁,并且锁住id=1,2行
 *  注意:行级锁语句必须是主键作为查询条件,才能启动行级锁,否则是表级锁(数据库序列化的时候启动表)
 * 3、作用:启动行级锁只有当前事务才可以修改i=1,2这条记录,在当前事务中修改
 * 4、commit,结束事务,释放行级锁
 *
 */



/**
 * 在jdbc中使用行级锁:
 * 1、执行语句:conn.setAutoCommit(false),关闭数据库自动提交
 * 2、执行语句:select * from users where id in(1,2) for update; 引起事务,启动行级锁,并且锁住id=1,2行
 *  注意:行级锁语句必须是主键作为查询条件,才能启动行级锁,否则是表级锁(数据库序列化的时候启动表)
 * 3、作用:启动行级锁只有当前事务才可以修改i=1,2这条记录,在当前事务中修改
 * 4、结束事务,释放行级锁
 *
 */

示例代码:

import com.csjin.edu.TestJDBC.Test02.util.jdbcUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


/**
 * 在数据库中使用行级锁:
 * 1、执行数据库语句:start transaction ,关闭数据库自动提交
 * 2、执行语句:select * from users where id in(1,2) for update; 引起事务,启动行级锁,并且锁住id=1,2行
 *  注意:行级锁语句必须是主键作为查询条件,才能启动行级锁,否则是表级锁(数据库序列化的时候启动表)
 * 3、作用:启动行级锁只有当前事务才可以修改i=1,2这条记录,在当前事务中修改
 * 4、commit,结束事务,释放行级锁
 *
 */



/**
 * 在jdbc中使用行级锁:
 * 1、执行语句:conn.setAutoCommit(false),关闭数据库自动提交
 * 2、执行语句:select * from users where id in(1,2) for update; 引起事务,启动行级锁,并且锁住id=1,2行
 *  注意:行级锁语句必须是主键作为查询条件,才能启动行级锁,否则是表级锁(数据库序列化的时候启动表)
 * 3、作用:启动行级锁只有当前事务才可以修改i=1,2这条记录,在当前事务中修改
 * 4、结束事务,释放行级锁
 *
 */

public class Test07 {

    public static void main(String[] args){
        test1();
    }

    private static void test1() {

        Connection conn = null;
        PreparedStatement pstate = null;
        ResultSet res = null;

        try {
            conn = jdbcUtil.getConnection();

            //开启事务,关闭自动提交
            conn.setAutoCommit(false);

            String sql = "select * from users where id =? for update";

            pstate = conn.prepareStatement(sql);
            pstate.setInt(1,2);

            pstate.executeQuery();

            sql = "update users set password=1234567 where id=?";
            pstate = conn.prepareStatement(sql);
            pstate.setInt(1,2);

            int i = pstate.executeUpdate();
            System.out.println("i="+i);


            //提交事务
            conn.commit();

        } catch (SQLException e) {
            System.err.println("事务SQLException异常信息如下:");
            e.printStackTrace();
            //手动回滚
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            System.out.println("事务ClassNotFoundException异常信息如下:");
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            jdbcUtil.closeDb(conn,pstate,null);
        }
    }
}
原文地址:https://www.cnblogs.com/chushujin/p/11603052.html