Java SE 07(JDBC、数据库连接池、Spring中的JdbcTemplate类)

Java SE 07

一、JDBC

JDBC概述

  • JDBC(Java Database Connectivity),全称Java数据库连接,就是使用Java语言操作数据库

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

  • JDBC使用步骤:

    1. 导入驱动jar包mysql-connector-java-5.1.37-bin.jar

      idea中操作步骤:

      1 复制jar包到项目目录下的自定义文件夹下
      2 右键这个文件夹 add as library

    2. 注册驱动

    3. 获取数据库连接对象Connection

    4. 定义sql

    5. 获取执行sql语句的对象Statement

    6. 执行sql,接收返回结果

    7. 处理结果

    8. 释放资源

    public class JdbcDemo01 {
        public static void main(String[] args) throws SQLException, ClassNotFoundException {
            //注册驱动jar包,在MySQL5之后可省略不写,原因:在jar包中META-INF文件夹中services下Driver类中有注册驱动jar包com.mysql.jdbc.Driver
            Class.forName("com.mysql.jdbc.Driver");
            
            Connection cnn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "root", "root");
    
            Statement stmt = cnn.createStatement();
            String sql = "UPDATE emp SET dept_id = 10 WHERE id = 1001";
            int count = stmt.executeUpdate(sql);
    
            System.out.println(count);
            stmt.close();
            cnn.close();
        }
    }
    

    代码中的各个对象:

    1. DriverManager:驱动管理对象

      功能:

      1. 注册驱动

        DriverManager中的静态方法

        static void registerDriver(Driver driver)使用DriverManager注册给定的驱动程序

        在com.mysql.jdbc.Driver的源码中有静态代码块,使用Class.forName会将该类加载,同时执行这个静态代码块,从而完成驱动的注册

        static {
         try {
             java.sql.DriverManager.registerDriver(new Driver());
         } catch (SQLException E) {
             throw new RuntimeException("Can't register driver!");
         }
        }
        
      2. 获取数据库连接

        DriverManager中的静态方法

        static Connection getConnection(String url, String user, String password)

        方法参数:url:指定连接的路径, user:用户名,password:密码

        url的格式:jdbc:mysql://ip地址(域名):端口号/数据库名称

        如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,

        url可以简写为jdbc:mysql:///数据库名称

    2. Connection:数据库连接对象

      Connection类中的方法

      1. 获取执行sql的对象

        Statement createStatement()

        PreparedStatement prepareStatement(Stirng sql)

      2. 管理事务

        • 开启事务

          setAutoCommit(boolean autocommit)

          调用该方法设置参数为false,就是开启事务

        • 提交事务

          commit()

        • 回滚事务

          rollback()

    3. Statement:执行sql的对象

      Statement类中的方法

      1. boolean execuate(String sql)可以执行任意的sql

      2. int execuateUpdate(String sql)执行DML(常用)、DDL(不常用)

        若传入DML的返回值:sql语句执行后影响的行数,可以通过这个影响的行数判断DML语句是否执行成功,返回值>0执行成功,否则执行失败。若传入的是DDL则return nothing

      3. ResultSet executeQuery(String sql)执行DQL语句(select)

    4. ResultSet:结果集对象

    5. PreparedStatement:执行sql的对象

JDBC中使用insert语句

  • 示例Code

    public class JdbcDemo02 {
        public static void main(String[] args) {
            Statement stat = null;
            Connection conn = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String sql = "INSERT INTO emp VALUES (1016, 'Jeff', 3, 1004, '2021-7-5', 9000, null, 30)";
                conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root");
                stat = conn.createStatement();
                int num = stat.executeUpdate(sql);
                if(num > 0) {
                    System.out.println("insert successfully!");
                } else {
                    System.out.println("fail to insert!");
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
              //这里使用finally来释放资源,不管try中的程序是否正常执行,最终到这里会释放资源
            } finally {
    			//若try中的程序没有正常释放资源,这里的引用类型的对象值仍为null,所以先判断防止空指针异常
                if(stat != null) {
                    try {
                        stat.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
                if(conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
            }
        }
    }
    /*output:在数据库db2的emp表中成功地插入了一条指定的数据
    insert successfully!
    */
    

JDBC中使用update语句

  • 示例Code

    //方法同上,只是改变了sql语句
    public class JdbcDemo03 {
    
            public static void main(String[] args) {
                Statement stat = null;
                Connection conn = null;
                try {
                    Class.forName("com.mysql.jdbc.Driver");
                    String sql = "UPDATE emp SET ename = 'Jack' WHERE id = 1016";
                    conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root");
                    stat = conn.createStatement();
                    int count = stat.executeUpdate(sql);
                    if(count > 0) {
                        System.out.println("update successfully!");
                    } else {
                        System.out.println("fail to update!");
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
    
                    if(stat != null) {
                        try {
                            stat.close();
                        } catch (SQLException throwables) {
                            throwables.printStackTrace();
                        }
                    }
    
                    if(conn != null) {
                        try {
                            conn.close();
                        } catch (SQLException throwables) {
                            throwables.printStackTrace();
                        }
                    }
    
                }
            }
    
    }
    /*output:在数据库db2的emp表中成功地修改了一条指定的字段值
    update successfully!
    */
    

JDBC中使用delete语句

  • 示例Code

    //方法同上,只是改变了sql语句
    public class JdbcDemo04 {
        public static void main(String[] args) {
            Statement stat = null;
            Connection conn = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String sql = "DELETE FROM emp WHERE id = 1016";
                conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root");
                stat = conn.createStatement();
                int count = stat.executeUpdate(sql);
                if(count > 0) {
                    System.out.println("delete successfully!");
                } else {
                    System.out.println("fail to delete!");
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
    
                if(stat != null) {
                    try {
                        stat.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
                if(conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
            }
        }
    }
    /*output:在数据库db2的emp表中成功地删除了一条指定的数据
    delete successfully!
    */
    

JDBC中使用DDL语句

  • 示例Code

    //方法几乎与上面例子,只是改变了sql语句
    //去除了executeUpdate方法的返回值判断,因为此时传入的参数是DDL的sql,返回nothing
    public class JdbcDemo05 {
        public static void main(String[] args) {
            Statement stat = null;
            Connection conn = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String sql = "CREATE TABLE tab_test(id INT, name VARCHAR(32))";
                conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root");
                stat = conn.createStatement();
                int count = stat.executeUpdate(sql);
                System.out.println("count = " + count);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
    
                if(stat != null) {
                    try {
                        stat.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
                if(conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
            }
        }
    }
    /*output:在数据库db2中创建新表tab_test
    count = 0
    */
    

ResultSet类

  • 通过Statement类的executeQuery方法返回ResultSet类的对象

    ResultSet executeQuery(String sql)执行DQL语句(select)

  • ResultSet类中的方法

    1. boolean next():游标向下移动一行,判断当前行是否是最后一行的末尾(是否有数据),如果是返回false,如果不是返回true

      使用步骤:

      1. 游标向下移动一行
      2. 判断是否有数据
      3. 获取数据
    2. getXxx(args):获取数据

      Xxx代表数据类型,如int getInt()String getString()

      args参数:

      (1) int:代表列的编号,从1开始,如:getString(1)
      (2) String:代表列的名称,如:getDouble(balance)

  • 示例Code

    //代码几乎同上面的例子,使用executeQuery方法返回ResultSet对象
    public class JdbcDemo06 {
        public static void main(String[] args) {
                Statement stat = null;
                Connection conn = null;
                ResultSet rs = null;
                try {
                    Class.forName("com.mysql.jdbc.Driver");
                    String sql = "SELECT * FROM emp";
                    conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root");
                    stat = conn.createStatement();
                    rs = stat.executeQuery(sql);
    				
                    //使用ResultSet类的方法,获取表中的数据
                    rs.next();
                    int id = rs.getInt(1);
                    String name = rs.getString(2);
                    System.out.println("id = " + id + ", name = " + name);
    
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
    				//释放创建ResultSet类对象所需的资源
                    if(rs != null) {
                        try {
                            rs.close();
                        } catch (SQLException throwables) {
                            throwables.printStackTrace();
                        }
                    }
    
                    if(stat != null) {
                        try {
                            stat.close();
                        } catch (SQLException throwables) {
                            throwables.printStackTrace();
                        }
                    }
    
                    if(conn != null) {
                        try {
                            conn.close();
                        } catch (SQLException throwables) {
                            throwables.printStackTrace();
                        }
                    }
    
                }
            }
    
    }
    /*output:
    显示查询到的表中的一行信息
    */
    
    public class JdbcDemo07 {
        public static void main(String[] args) {
            Statement stat = null;
            Connection conn = null;
            ResultSet rs = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String sql = "SELECT * FROM emp";
                conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root");
                stat = conn.createStatement();
                rs = stat.executeQuery(sql);
    
                while(rs.next()) {
                    int id = rs.getInt(1);
                    String name = rs.getString(2);
                    System.out.println("id = " + id + ", name = " + name);
                }
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
    
                if(rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
                if(stat != null) {
                    try {
                        stat.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
                if(conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
            }
        }
    }
    /*output:
    显示查询到的表中的多行信息(指定的几列,循环遍历打印)
    */
    

JDBC实例

  • 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回

  • 实现步骤:

    1 定义Emp类
    2 定义方法public List<Emp> getAllInfo(){}
    3 使用的sql语句select * from emp;

  • 实例Code

    //将数据库表emp中的字段,作为Emp表这个类的各个成员变量
    public class Emp {
        private int id;
        private String eName;
        private int job_id;
        private int mgr;
        private Date date;
        private double salary;
        private double bonus;
        private int dept_id;
    
        public Emp() {
        }
    
        @Override
        public String toString() {
            return "emp{" +
                    "id=" + id +
                    ", eName='" + eName + '\'' +
                    ", job_id=" + job_id +
                    ", mgr=" + mgr +
                    ", date=" + date +
                    ", salary=" + salary +
                    ", bonus=" + bonus +
                    ", dept_id=" + dept_id +
                    '}';
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String geteName() {
            return eName;
        }
    
        public void seteName(String eName) {
            this.eName = eName;
        }
    
        public int getJob_id() {
            return job_id;
        }
    
        public void setJob_id(int job_id) {
            this.job_id = job_id;
        }
    
        public int getMgr() {
            return mgr;
        }
    
        public void setMgr(int mgr) {
            this.mgr = mgr;
        }
    
        public Date getDate() {
            return date;
        }
    
        public void setDate(Date date) {
            this.date = date;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
        public double getBonus() {
            return bonus;
        }
    
        public void setBonus(double bonus) {
            this.bonus = bonus;
        }
    
        public int getDept_id() {
            return dept_id;
        }
    
        public void setDept_id(int dept_id) {
            this.dept_id = dept_id;
        }
    }
    
    public class JdbcDemo08 {
        public static void main(String[] args) {
            JdbcDemo08 jdbcDemo08 = new JdbcDemo08();
            List<Emp> allInfo = jdbcDemo08.getAllInfo();
            //System.out.println(allInfo);
            for(Emp ele : allInfo) {
                System.out.println(ele);
            }
        }
    
        public List<Emp> getAllInfo() {
            List<Emp> list = new ArrayList<>();
            Connection conn = null;
            Statement stmt = null;
            ResultSet resultSet = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root", "root");
                stmt = conn.createStatement();
                String sql = "SELECT * FROM emp";
                resultSet = stmt.executeQuery(sql);
                Emp emp = null;
                while(resultSet.next()) {
                    emp = new Emp();
                    int id = resultSet.getInt("id");
                    emp.setId(id);
                    String eName = resultSet.getString("ename");
                    emp.seteName(eName);
                    int jobID = resultSet.getInt("job_id");
                    emp.setJob_id(jobID);
                    int mgr = resultSet.getInt("mgr");
                    emp.setMgr(mgr);
                    Date joinDate = resultSet.getDate("joindate");
                    emp.setDate(joinDate);
                    Double salary = resultSet.getDouble("salary");
                    emp.setSalary(salary);
                    Double bonus = resultSet.getDouble("bonus");
                    emp.setBonus(bonus);
                    int deptID = resultSet.getInt("dept_id");
                    emp.setDept_id(deptID);
                    list.add(emp);//将表中每一行信息添加到集合中
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                if(resultSet != null) {
                    try {
                        resultSet.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
                if(stmt != null) {
                    try {
                        stmt.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
    
                if(conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
            }
    
            return list;
        }
    }
    

JDBC工具类

  • 可以设计一个工具类JdbcUtilities,其中有以下方法

    1. 注册驱动

    2. 获取连接对象

      可以使用配置文件,读取参数,为getConnection(String url, String username, String password)方法传参

    3. 释放资源

  • 示例Code

    public class JdbcUtilities {
        private static String url = null;
        private static String username = null;
        private static String password = null;
        private static String driver =null;
        static {
            try {
                ClassLoader classLoader = JdbcUtilities.class.getClassLoader();
    
                //InputStream is = classLoader.getResourceAsStream("JDBC.properties");
                URL resource = classLoader.getResource("JDBC.properties");
                String path = resource.getPath();
    
                Properties properties = new Properties();
    
                //properties.load(is);
                properties.load(new FileReader(path));
    
                url = properties.getProperty("url");
                username = properties.getProperty("username");
                password = properties.getProperty("password");
                driver = properties.getProperty("driver");
    
                Class.forName(driver);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        public static Connection getConn() throws SQLException, IOException {
    
            Connection conn = DriverManager.getConnection(url, username, password);
            return conn;
        }
    
        public static void close(ResultSet rs, Statement stmt, Connection conn){
            if(rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if(stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
        }
    }
    
    //使用JDBC工具类重做之前的JDBC实例
    public class JdbcDemo09 {
        public static void main(String[] args) {
            JdbcDemo08 jdbcDemo08 = new JdbcDemo08();
            List<Emp> allInfo = jdbcDemo08.getAllInfo();
            //System.out.println(allInfo);
            for(Emp ele : allInfo) {
                System.out.println(ele);
            }
        }
    
        public List<Emp> getAllInfo() {
            List<Emp> list = new ArrayList<>();
            Connection conn = null;
            Statement stmt = null;
            ResultSet resultSet = null;
    
            try {
                //Class.forName("com.mysql.jdbc.Driver");
                //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root", "root");
                conn = JdbcUtilities.getConn();
    
                stmt = conn.createStatement();
                String sql = "SELECT * FROM emp";
                resultSet = stmt.executeQuery(sql);
                Emp emp = null;
                while(resultSet.next()) {
    
                    int id = resultSet.getInt("id");
                    String eName = resultSet.getString("ename");
                    int jobID = resultSet.getInt("job_id");
                    int mgr = resultSet.getInt("mgr");
                    Date joinDate = resultSet.getDate("joindate");
                    Double salary = resultSet.getDouble("salary");
                    Double bonus = resultSet.getDouble("bonus");
                    int deptID = resultSet.getInt("dept_id");
    
                    emp = new Emp();
                    emp.setId(id);
                    emp.seteName(eName);
                    emp.setJob_id(jobID);
                    emp.setMgr(mgr);
                    emp.setDate(joinDate);
                    emp.setSalary(salary);
                    emp.setBonus(bonus);
                    emp.setDept_id(deptID);
    
                    list.add(emp);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                JdbcUtilities.close(resultSet, stmt, conn);
            }
    
            return list;
        }
    }
    

JDBC登录案例

  • 实现需求:

    1. 通过键盘输入用户名和密码
    2. 判断用户是否登录成功
  • 示例Code

    #该案例使用的表
    CREATE TABLE user(
    	id INT PRIMARY KEY AUTO_INCREMENT,
        username VARCHAR(32),
    	password VARCHAR(32)
    );
    
    INSERT INTO user VALUES (null, "33", "a3b3");
    INSERT INTO user VALUES (null, "34", "qwer");
    
    public class JdbcDemo10 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            String str1 = scanner.next();
            String str2 = scanner.next();
            boolean returnValue = new JdbcDemo10().userLogin(str1, str2);
            if(returnValue) {
                System.out.println("successfully login");
            } else {
                System.out.println("fail to login");
            }
        }
    
        public boolean userLogin(String name, String password) {
            if(name == null || password == null) {
                return false;
            }
            Connection conn = null;
            Statement statement = null;
            ResultSet resultSet = null;
            try {
                conn = JdbcUtilities.getConn();
                statement = conn.createStatement();
                //字符串拼接,使用传入的参数name和password
                String sql = "select * from user where username = '"+name+"' and password = '"+password+"' ";
                resultSet = statement.executeQuery(sql);
                //next方法返回值为boolean,若有sql中查询的一行则返回true,否则返回false
                return resultSet.next();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                JdbcUtilities.close(resultSet, statement, conn);
            }
    
            return false;
        }
    }
    //存在sql注入问题
    
    /*input:
    dhuf
    dbv' or 'ac' = 'ac
    */
    
    /*output:
    select * from user where username = 'dhuf' and password = 'dbv' or 'ac' = 'ac' 
    successfully login
    */
    

PreparedStatement类

  • PreparedStatement类是Statement类的子类

  • 作用:作用同Statement类都是执行sql的对象,但同时解决了sql注入问题

  • sql注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全问题

    在以上的例程中都使用了Statement类方法来执行sql的对象,但是输入特殊字符拼接,可以导致强行登录的问题

    //JDBC登录案例,控制台打印信息
    ahsdjh//输入任意用户名
    abcd' or 'ghgh' = 'ghgh//输入密码
    select * from user where username = 'ahsdjh' and password = 'abcd' or 'ghgh' = 'ghgh' //or右边的比较是恒成立的,or优先级高于and,所以where后面表达式为true,相当于where失效
    successfully login//成功登录
    
  • 使用PreparedStatement对象解决sql注入的问题

    • 使用预编译的sql,格式:参数使用?作为占位符

    • 使用步骤:

      1. 导入驱动jar包mysql-connector-java-5.1.37-bin.jar

      2. 注册驱动

      3. 获取数据库连接对象Connection

      4. 定义sql

        注意:sql的参数使用?作为占位符

        select * from user where username = ? and password = ?;

      5. 获取执行sql语句的对象PreparedStatement

        Connection类对象.preparedStatement(String sql)

      6. ?赋值

        使用PreparedStatement类的方法:setXxx(参数1,参数2)

        参数1:?的位置索引从1开始

        参数2:?的值

      7. 执行sql,接收返回结果

        PreparedStatement类中execute之类的方法无参数

        PreparedStatement中继承自Statement中的方法有参数,但此时不用这些方法,用子类中的无参数方法

      8. 处理结果

      9. 释放资源

    • 注意:

      后期都会使用PreparedStatement来完成增删改查的所有操作

      1. 可以防止sql注入
      2. 效率更高
  • 示例Code

    public class JdbcDemo11 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            String str1 = scanner.nextLine();
            String str2 = scanner.nextLine();
            boolean returnValue = new JdbcDemo11().userLogin(str1, str2);
            if(returnValue) {
                System.out.println("successfully login");
            } else {
                System.out.println("fail to login");
            }
        }
    
        public boolean userLogin(String name, String password) {
            if(name == null || password == null) {
                return false;
            }
            Connection conn = null;
            PreparedStatement pStmt = null;
            ResultSet resultSet = null;
            try {
                conn = JdbcUtilities.getConn();
                String sql = "select * from user where username = ? and password = ? ";
                pStmt = conn.prepareStatement(sql);
                //System.out.println(sql);
                pStmt.setString(1, name);
                pStmt.setString(2, password);
                resultSet = pStmt.executeQuery();
                return resultSet.next();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                JdbcUtilities.close(resultSet, pStmt, conn);//这里pStmt传参,父类引用指向子类对象,多态
            }
    
            return false;
        }
    }
    /*input:
    dhfjd
    ap' or 'aaa' = 'aaa
    */
    
    /*output:
    select * from user where username = ? and password = ? 
    fail to login
    */
    

JDBC管理事务

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

  • 管理事务的操作:

    1. 开启事务
    2. 提交事务
    3. 回滚事务
  • 使用Connection类中的方法来管理事务

    • 开启事务:在代码中,执行sql之前开启事务

      setAutoCommit(boolean autocommit)

      调用该方法设置参数为false,就是开启事务

    • 提交事务:在代码中,当所有sql都执行完提交事务

      commit()

    • 回滚事务:在代码中,在异常处理的catch中回滚事务

      rollback()

  • 示例Code

    public class JdbcDemo12 {
        public static void main(String[] args) {
            new JdbcDemo12().transfer();
        }
    
        public void transfer() {
            Connection conn = null;
            PreparedStatement pStmt1 = null;
            PreparedStatement pStmt2 = null;
            try {
                conn = JdbcUtilities.getConn();
                conn.setAutoCommit(false);
                String sql1 = "UPDATE account SET balance = balance - ? WHERE id = ?";
                String sql2 = "UPDATE account SET balance = balance + ? WHERE id = ?";
                pStmt1 = conn.prepareStatement(sql1);
                pStmt2 = conn.prepareStatement(sql2);
                pStmt1.setDouble(1, 500);
                pStmt2.setDouble(1, 500);
                pStmt1.setInt(2, 1);
                pStmt2.setInt(2, 2);
                pStmt1.executeUpdate();
    
                /*在两次转账操作间设置异常操作
                String str = null;
                str.toLowerCase();*/
    
                pStmt2.executeUpdate();
                conn.commit();
           /* } catch (SQLException throwables) {
                throwables.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();  */
            }catch (Exception e) {
                try {
                    //catch中设置回滚事务
                    if(conn != null) {
                        conn.rollback();
                    }
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                JdbcUtilities.close(pStmt1, conn);
                JdbcUtilities.close(pStmt2, null);
            }
        }
    }
    

二、数据库连接池

数据库连接池概述

  • 数据库连接池就是一个容器(集合),存放数据库连接的容器。

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

  • 数据库连接池的好处

    1. 节约资源
    2. 用户访问高效
  • 数据库连接池的实现

    • 标准接口DataSource,在javax.sql包下的

      • 方法:

        获取连接:getConnection()

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

    • 一般普通开发者不去实现它,由数据库厂商实现

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

数据库连接池c3p0

  • 使用步骤

    1. 导入jar包c3p0-0.9.5.2.jar和依赖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. 创建核心对象,即数据库连接池对象ComboPooledDataSource

      该构造方法中无参是读取默认配置,若有String参数是传入指定配置的配置名称来使用指定配置

    4. 获取连接:getConnection

  • 示例Code

    //示例1:使用连接池
    public class Demo01c3p0 {
        public static void main(String[] args) throws SQLException {
            //创建数据库连接池对象
            DataSource ds = new ComboPooledDataSource();
            //获取连接对象
            Connection connection = ds.getConnection();
            System.out.println(connection);
        }
    }
    /*output:打印日志信息 和 connection对象的信息
    
    Jul 08, 2021 10:57:59 PM com.mchange.v2.log.MLog 
    INFO: MLog clients using java 1.4+ standard logging.
    Jul 08, 2021 10:58:00 PM com.mchange.v2.c3p0.C3P0Registry 
    INFO: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
    Jul 08, 2021 10:58:00 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 
    INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 3000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1b60699ai11cqj5idnrclk|525b461a, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1b60699ai11cqj5idnrclk|525b461a, idleConnectionTestPeriod -> 0, initialPoolSize -> 5, jdbcUrl -> jdbc:mysql://localhost:3306/db3, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {password=******, user=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
    com.mchange.v2.c3p0.impl.NewProxyConnection@11bd0f3b [wrapping: com.mysql.jdbc.JDBC4Connection@c333c60]
    */
    
    //示例2:根据XML配置文件中的信息测试最大连接
    public class Demo02c3p0 {
        public static void main(String[] args) throws SQLException {
    //        DataSource ds = new ComboPooledDataSource();
    //        for(int i = 0; i < 10; i++) {
    //            Connection connection = ds.getConnection();
    //            System.out.println(i + ":" + connection);
    //        }
    
            testMaxPoolSize1();
            //testMaxPoolSize2();
        }
    
        public static void testMaxPoolSize1() throws SQLException {
            //这里使用无参数构造创建对象,使用默认配置的配置信息,XML中最大连接数为10
            DataSource ds = new ComboPooledDataSource();
            for(int i = 0; i < 11; i++) {
                Connection connection = ds.getConnection();
                System.out.println(i + ":" + connection);
    
                //这里第6次连接后关闭,这样可以总共连接11个
                if(i == 5) {
                    connection.close();
                }
            }
        }
    
        public static void testMaxPoolSize2() throws SQLException {
            //使用指定的配置"otherc3p0"中的配置信息,XML中最大连接数为8
            DataSource ds = new ComboPooledDataSource("otherc3p0");
            for(int i = 0; i < 9; i++) {
                Connection connection = ds.getConnection();
                System.out.println(i + ":" + connection);
    
                //这里第6次连接后关闭,这样可以总共连接9个
                if(i == 5) {
                    connection.close();
                }
            }
        }
    
    }
    
    <c3p0-config>
      <!-- 使用默认的配置读取连接池对象 -->
      <default-config>
      	<!--  连接参数 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property>
        <property name="user">root</property>
        <property name="password">root</property>
        
        <!-- 连接池参数 -->
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">10</property>
        <property name="checkoutTimeout">3000</property>
      </default-config>
    
      <named-config name="otherc3p0"> 
        <!--  连接参数 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property>
        <property name="user">root</property>
        <property name="password">root</property>
        
        <!-- 连接池参数 -->
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">8</property>
        <property name="checkoutTimeout">1000</property>
      </named-config>
    </c3p0-config>
    

数据库连接池Druid

  • 使用步骤

    1. 导入jar包druid-1.0.9.jar

    2. 定义配置文件:

      druid.properties

      是properties格式的,可以放在任意目录下

    3. 加载配置文件

      通过Properties中的load方法

    4. 获取数据库连接池对象:

      通过工厂类DruidDataSourceFactory中的静态方法createDataSource

    5. 获取连接:

      通过DataSource类中的getConnection方法

  • 示例Code

    public class Demo03Druid {
        public static void main(String[] args) throws Exception {
            //加载配置文件
            InputStream is = Demo03Druid.class.getClassLoader().getResourceAsStream("druid.properties");
            Properties prop = new Properties();
            prop.load(is);
    
            //获取连接池对象
            DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
            //获取连接
            Connection connection = dataSource.getConnection();
            //打印连接对象
            System.out.println(connection);
        }
    }
    /*output:
    Jul 09, 2021 3:35:42 PM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    com.mysql.jdbc.JDBC4Connection@6c40365c
    */
    

Druid工具类

  • 定义工具类的实现步骤:

    1. 定义一个类JDBCUtils
    2. 提供静态代码块加载配置文件,初始化连接池对象
    3. 提供方法
      • 获取连接的方法:通过数据库连接池获取
      • 释放资源
      • 获取连接池的方法
  • 示例Code

    public class JDBCUtils {
        //定义成员变量DataSource
        private static DataSource ds;
    
        static {
    
            try {
                //加载配置文件
                Properties prop = new Properties();
                prop.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
                //获取DataSource
                ds = DruidDataSourceFactory.createDataSource(prop);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //获取连接池对象ds
        public static DataSource getDataSource() {
            return ds;
        }
    
        //获取连接
        public static Connection getConnection() throws SQLException {
            return ds.getConnection();
        }
    
        //释放资源,使用executeQuery会返回ResultSet对象
        public static void close(Connection conn, Statement stmt, ResultSet rs) {
            if(rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if(stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    	//释放资源,使用executeUpdate
        //这里方法体直接调用了上面定义的3个参数的方法重载形式
        public static void close(Connection conn, Statement stmt) {
            close(conn, stmt, null);
        }
    }
    
  • 测试Druid工具类

    //为数据库db3中的表account添加一条数据
    public class Demo04TestDruid {
    
        public static void main(String[] args) {
            Connection connection = null;
            PreparedStatement pstmt = null;
            try {
                connection = JDBCUtils.getConnection();
                String sql = "INSERT INTO account VALUES (null, ?, ?)";
                pstmt = connection.prepareStatement(sql);
                pstmt.setString(1, "Lucy");
                pstmt.setDouble(2, 3500);
                int count = pstmt.executeUpdate();
                System.out.println(count);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                JDBCUtils.close(connection, pstmt);
            }
    
        }
    }
    /*output:返回1表示表中有一条改动
    
    Jul 09, 2021 4:57:44 PM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    1
    */
    

三、Spring中的JdbcTemplate类

JdbcTemplate概述

  • Spring JDBC是Spring框架对JDBC的简单封装,其中提供了一个JdbcTemplate类简化JDBC的开发

  • 使用步骤:

    1. 导入jar包

      • commons-logging-1.2.jar
      • spring-beans-5.0.0.RELEASE.jar
      • spring-core-5.0.0.RELEASE.jar
      • spring-jdbc-5.0.0.RELEASE.jar
      • spring-tx-5.0.0.RELEASE.jar

      同时需要有导入的数据库驱动jar包mysql-connector-java-5.1.37-bin.jar

    2. 创建JdbcTemplate对象,这个对象依赖于数据库连接池(数据源)DataSource

      JdbcTemplate template = new JdbcTemplate(ds);

    3. 调用JdbcTemplate的方法来完成CRUD的操作

      • update():执行DML语句(增删改语句)

      • queryForMap():将查询到的结果集封装为Map集合,其中列名为key,值作为value

        注意:这个方法查询的结果集长度只能是1, 例如queryForMap(sql语句字符串, arg参数)

      • queryForList():将查询到的结果集封装为List集合

        注意:将每一条记录封装为一个Map集合,再将Map结合装载到List集合中

      • query():查询结果,将结果封装为JavaBean对象

        方法query的参数:RowMapper接口类型的对象

        一般使用BeanPropertyRowMapper实现类,可以完成数据到JavaBean的自动封装

        格式:new BeanPropertyRowMapper<类型>(类型.class)

      • queryForObject():查询结果,将结果封装为对象

        多用于使用了聚合函数的查询

  • 示例Code

    public class TestJdbcTemplate {
        public static void main(String[] args) throws Exception {
            //创建JdbcTemplate对象
            DataSource dataSource = JDBCUtils.getDataSource();
            JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
            
            //调用JdbcTemplate对象中的方法
            String sql = "UPDATE account SET balance = 100 WHERE id = ?";
            //update方法中传入sql语句和sql语句中的参数
            int update = jdbcTemplate.update(sql, 3);
            System.out.println(update);
        }
    }
    /*output:返回1表示表中有一条改动
    
    Jul 09, 2021 5:36:58 PM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    1
    */
    

JdbcTemplate执行DML语句

  • Jdbc Template执行DML语句的方法:

    update():执行DML语句(增删改语句)

  • 示例Code

    //使用Junit单元测试,单独测试JdbcTemplate类中的增、删、改方法
    public class JdbcTemplateTest {
    
        private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
    
        //更改一条数据
        @Test
        public void testUpdate1() {
            String sql = "UPDATE emp SET salary = 10000 WHERE id = 1001";
            int count = jdbcTemplate.update(sql);
            System.out.println(count);
        }
        
        /*output:
        Jul 09, 2021 9:50:29 PM com.alibaba.druid.pool.DruidDataSource info
    	INFO: {dataSource-1} inited
    	1
        */
    
        //插入一条数据
        @Test
        public void testUpdate2() {
            String sql = "INSERT INTO emp (id, ename, dept_id) VALUES(?, ?, ?)";
            int count = jdbcTemplate.update(sql, 1016, "Jake", 10);
            System.out.println(count);
        }
        
        /*output:
        Jul 09, 2021 9:51:40 PM com.alibaba.druid.pool.DruidDataSource info
    	INFO: {dataSource-1} inited
    	1
        */
    
        //删除一条数据
        @Test
        public void testUpdate3() {
            String sql = "DELETE FROM emp WHERE ename = ?";
            int count = jdbcTemplate.update(sql, "Jake");
            System.out.println(count);
        }
        
        /*output:
        Jul 09, 2021 9:52:39 PM com.alibaba.druid.pool.DruidDataSource info
    	INFO: {dataSource-1} inited
    	1
        */
    }
    

JdbcTemplate执行DQL语句

  • Jdbc Template执行DQL语句的方法:

    • queryForMap():将查询到的结果集封装为Map集合,其中列名为key,值作为value

      注意:这个方法查询的结果集长度只能是1, 例如queryForMap(sql语句字符串, arg参数)

    • queryForList():将查询到的结果集封装为List集合

      注意:将每一条记录封装为一个Map集合,再将Map结合装载到List集合中

    • query()查询结果,将结果封装为JavaBean对象,此方法需要使用一个预定义的类(成员变量为表中的字段,类中包含getter和setter方法、toString方法的重写)

      方法query的参数:需要传入RowMapper接口类型的对象,可以自定义实现类(或者用匿名内部类),也可以使用一些给定的实现类

      一般使用BeanPropertyRowMapper实现类,可以完成数据到JavaBean的自动封装

      格式:new BeanPropertyRowMapper<类型>(类型.class)

      注意:预定义的类型中,类的成员变量必须是引用类型,若有基本数据类型要使用其对应的包装类

      否则会出现org.springframework.beans.TypeMismatchException

    • queryForObject():查询结果,将结果封装为对象

      一般用于使用了聚合函数的查询

  • 示例Code

    //queryForMap():将查询到的结果集封装为Map集合,其中列名为key,值作为value
    //这个方法查询的结果集长度只能是1,  例如:queryForMap(sql语句字符串, arg参数),预编译sql参数只能有一个
    public class TestJdbcTemplate2 {
    
        private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
    
        @Test
        public void testQueryForMap() {
            String sql = "SELECT * FROM emp WHERE id = ?";
            //这里只能是查询一个id中的记录
            Map<String, Object> map = jdbcTemplate.queryForMap(sql, 1001);
    
            //打印map
            System.out.println(map);
            //遍历打印map中的key和value
            for(String ele : map.keySet()) {
                System.out.println(ele + ":" + map.get(ele));
            }
        }
    }
    /*output:打印日志信息+测试类中测试方法执行输出结果
    Jul 09, 2021 11:14:58 PM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    {id=1001, ename=George, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=10}
    ===========
    id:1001
    ename:George
    job_id:4
    mgr:1004
    joindate:2000-12-17
    salary:10000.00
    bonus:null
    dept_id:10
    */
    
    //queryForList(String sql):将查询到的结果集封装为List集合
    public class TestJdbcTemplate2 {
        @Test
        public void testQueryForList() {
            String sql = "SELECT * FROM emp";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
    
            //打印这个list
            System.out.println(list);
            System.out.println("=============");
            //遍历打印这个list中的元素
            for(Map<String, Object> ele : list) {
                System.out.println(ele);
            }
        }
    }
    /*output:打印日志信息+测试类中测试方法执行输出结果
    Jul 09, 2021 11:10:26 PM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    [{id=1001, ename=George, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=10}, {id=1002, ename=卢俊义, job_id=3, mgr=1006, joindate=2001-02-20, salary=16000.00, bonus=3000.00, dept_id=10}, {id=1003, ename=林冲, job_id=3, mgr=1006, joindate=2001-02-22, salary=12500.00, bonus=5000.00, dept_id=30}, {id=1004, ename=唐僧, job_id=2, mgr=1009, joindate=2001-04-02, salary=29750.00, bonus=null, dept_id=20}, {id=1005, ename=李逵, job_id=4, mgr=1006, joindate=2001-09-28, salary=12500.00, bonus=14000.00, dept_id=30}, {id=1006, ename=宋江, job_id=2, mgr=1009, joindate=2001-05-01, salary=28500.00, bonus=null, dept_id=30}, {id=1007, ename=刘备, job_id=2, mgr=1009, joindate=2001-09-01, salary=24500.00, bonus=null, dept_id=10}, {id=1008, ename=猪八戒, job_id=4, mgr=1004, joindate=2007-04-19, salary=30000.00, bonus=null, dept_id=20}, {id=1009, ename=罗贯中, job_id=1, mgr=null, joindate=2001-11-17, salary=50000.00, bonus=null, dept_id=10}, {id=1010, ename=吴用, job_id=3, mgr=1006, joindate=2001-09-08, salary=15000.00, bonus=0.00, dept_id=30}, {id=1011, ename=沙僧, job_id=4, mgr=1004, joindate=2007-05-23, salary=11000.00, bonus=null, dept_id=20}, {id=1012, ename=李逵, job_id=4, mgr=1006, joindate=2001-12-03, salary=9500.00, bonus=null, dept_id=30}, {id=1013, ename=小白龙, job_id=4, mgr=1004, joindate=2001-12-03, salary=30000.00, bonus=null, dept_id=20}, {id=1014, ename=关羽, job_id=4, mgr=1007, joindate=2002-01-23, salary=13000.00, bonus=null, dept_id=10}, {id=1015, ename=悟, job_id=null, mgr=1004, joindate=2000-12-17, salary=8000.00, bonus=null, dept_id=20}]
    =============
    {id=1001, ename=George, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=10}
    {id=1002, ename=卢俊义, job_id=3, mgr=1006, joindate=2001-02-20, salary=16000.00, bonus=3000.00, dept_id=10}
    {id=1003, ename=林冲, job_id=3, mgr=1006, joindate=2001-02-22, salary=12500.00, bonus=5000.00, dept_id=30}
    {id=1004, ename=唐僧, job_id=2, mgr=1009, joindate=2001-04-02, salary=29750.00, bonus=null, dept_id=20}
    {id=1005, ename=李逵, job_id=4, mgr=1006, joindate=2001-09-28, salary=12500.00, bonus=14000.00, dept_id=30}
    {id=1006, ename=宋江, job_id=2, mgr=1009, joindate=2001-05-01, salary=28500.00, bonus=null, dept_id=30}
    {id=1007, ename=刘备, job_id=2, mgr=1009, joindate=2001-09-01, salary=24500.00, bonus=null, dept_id=10}
    {id=1008, ename=猪八戒, job_id=4, mgr=1004, joindate=2007-04-19, salary=30000.00, bonus=null, dept_id=20}
    {id=1009, ename=罗贯中, job_id=1, mgr=null, joindate=2001-11-17, salary=50000.00, bonus=null, dept_id=10}
    {id=1010, ename=吴用, job_id=3, mgr=1006, joindate=2001-09-08, salary=15000.00, bonus=0.00, dept_id=30}
    {id=1011, ename=沙僧, job_id=4, mgr=1004, joindate=2007-05-23, salary=11000.00, bonus=null, dept_id=20}
    {id=1012, ename=李逵, job_id=4, mgr=1006, joindate=2001-12-03, salary=9500.00, bonus=null, dept_id=30}
    {id=1013, ename=小白龙, job_id=4, mgr=1004, joindate=2001-12-03, salary=30000.00, bonus=null, dept_id=20}
    {id=1014, ename=关羽, job_id=4, mgr=1007, joindate=2002-01-23, salary=13000.00, bonus=null, dept_id=10}
    {id=1015, ename=悟, job_id=null, mgr=1004, joindate=2000-12-17, salary=8000.00, bonus=null, dept_id=20}
    /
    
    //query(String sql, RowMapper<T> rowMapper):查询结果,将结果封装为JavaBean对象
    //这里使用的是给定的实现类BeanPropertyRowMapper
    public class TestJdbcTemplate2 {
        @Test
        public void testQuery() {
            String sql = "SELECT * FROM emp";
            List<Emp> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
            System.out.println(query);
        }
    }
    /*output:打印日志信息+测试类中测试方法执行输出结果
    Jul 09, 2021 11:44:01 PM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    [Emp{id=1001, eName='George', job_id=4, mgr=1004, date=null, salary=10000.0, bonus=null, dept_id=10}, Emp{id=1002, eName='卢俊义', job_id=3, mgr=1006, date=null, salary=16000.0, bonus=3000.0, dept_id=10}, Emp{id=1003, eName='林冲', job_id=3, mgr=1006, date=null, salary=12500.0, bonus=5000.0, dept_id=30}, Emp{id=1004, eName='唐僧', job_id=2, mgr=1009, date=null, salary=29750.0, bonus=null, dept_id=20}, Emp{id=1005, eName='李逵', job_id=4, mgr=1006, date=null, salary=12500.0, bonus=14000.0, dept_id=30}, Emp{id=1006, eName='宋江', job_id=2, mgr=1009, date=null, salary=28500.0, bonus=null, dept_id=30}, Emp{id=1007, eName='刘备', job_id=2, mgr=1009, date=null, salary=24500.0, bonus=null, dept_id=10}, Emp{id=1008, eName='猪八戒', job_id=4, mgr=1004, date=null, salary=30000.0, bonus=null, dept_id=20}, Emp{id=1009, eName='罗贯中', job_id=1, mgr=null, date=null, salary=50000.0, bonus=null, dept_id=10}, Emp{id=1010, eName='吴用', job_id=3, mgr=1006, date=null, salary=15000.0, bonus=0.0, dept_id=30}, Emp{id=1011, eName='沙僧', job_id=4, mgr=1004, date=null, salary=11000.0, bonus=null, dept_id=20}, Emp{id=1012, eName='李逵', job_id=4, mgr=1006, date=null, salary=9500.0, bonus=null, dept_id=30}, Emp{id=1013, eName='小白龙', job_id=4, mgr=1004, date=null, salary=30000.0, bonus=null, dept_id=20}, Emp{id=1014, eName='关羽', job_id=4, mgr=1007, date=null, salary=13000.0, bonus=null, dept_id=10}, Emp{id=1015, eName='悟', job_id=null, mgr=1004, date=null, salary=8000.0, bonus=null, dept_id=20}]
    */
    
    //query(String sql, RowMapper<T> rowMapper):查询结果,将结果封装为JavaBean对象
    //使用匿名内部类实现RowMapper接口,需要重写mapRow方法,效果同上个例程
    //这种写法类似于之前的“JDBC实例”和“JDBC工具类”中的写法
    public class TestJdbcTemplate2 {
        @Test
        public void testQuery2() {
            String sql = "SELECT * FROM emp";
            List<Emp> query = jdbcTemplate.query(sql, new RowMapper<Emp>() {
                @Override
                public Emp mapRow(ResultSet resultSet, int i) throws SQLException {
                    Emp emp = new Emp();
                    int id = resultSet.getInt("id");
                    String eName =  resultSet.getString("ename");
                    int job_id = resultSet.getInt("job_id");
                    int mgr = resultSet.getInt("mgr");
                    Date date = resultSet.getDate("joindate");
                    Double salary = resultSet.getDouble("salary");
                    Double bonus = resultSet.getDouble("bonus");
                    int dept_id = resultSet.getInt("dept_id");
    
                    emp.setId(id);
                    emp.seteName(eName);
                    emp.setJob_id(job_id);
                    emp.setMgr(mgr);
                    emp.setDate(date);
                    emp.setSalary(salary);
                    emp.setBonus(bonus);
                    emp.setDept_id(dept_id);
                    return emp;
                }
            });
            System.out.println(query);
        }
    }
    /*output:打印日志信息+测试类中测试方法执行输出结果
    Jul 10, 2021 12:14:08 AM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    [Emp{id=1001, eName='George', job_id=4, mgr=1004, date=2000-12-17, salary=10000.0, bonus=0.0, dept_id=10}, Emp{id=1002, eName='卢俊义', job_id=3, mgr=1006, date=2001-02-20, salary=16000.0, bonus=3000.0, dept_id=10}, Emp{id=1003, eName='林冲', job_id=3, mgr=1006, date=2001-02-22, salary=12500.0, bonus=5000.0, dept_id=30}, Emp{id=1004, eName='唐僧', job_id=2, mgr=1009, date=2001-04-02, salary=29750.0, bonus=0.0, dept_id=20}, Emp{id=1005, eName='李逵', job_id=4, mgr=1006, date=2001-09-28, salary=12500.0, bonus=14000.0, dept_id=30}, Emp{id=1006, eName='宋江', job_id=2, mgr=1009, date=2001-05-01, salary=28500.0, bonus=0.0, dept_id=30}, Emp{id=1007, eName='刘备', job_id=2, mgr=1009, date=2001-09-01, salary=24500.0, bonus=0.0, dept_id=10}, Emp{id=1008, eName='猪八戒', job_id=4, mgr=1004, date=2007-04-19, salary=30000.0, bonus=0.0, dept_id=20}, Emp{id=1009, eName='罗贯中', job_id=1, mgr=0, date=2001-11-17, salary=50000.0, bonus=0.0, dept_id=10}, Emp{id=1010, eName='吴用', job_id=3, mgr=1006, date=2001-09-08, salary=15000.0, bonus=0.0, dept_id=30}, Emp{id=1011, eName='沙僧', job_id=4, mgr=1004, date=2007-05-23, salary=11000.0, bonus=0.0, dept_id=20}, Emp{id=1012, eName='李逵', job_id=4, mgr=1006, date=2001-12-03, salary=9500.0, bonus=0.0, dept_id=30}, Emp{id=1013, eName='小白龙', job_id=4, mgr=1004, date=2001-12-03, salary=30000.0, bonus=0.0, dept_id=20}, Emp{id=1014, eName='关羽', job_id=4, mgr=1007, date=2002-01-23, salary=13000.0, bonus=0.0, dept_id=10}, Emp{id=1015, eName='悟', job_id=0, mgr=1004, date=2000-12-17, salary=8000.0, bonus=0.0, dept_id=20}]
    */
    
    //queryForObject(String sql, Class<T> requiredType):查询结果,将结果封装为对象
    public class TestJdbcTemplate2 {
        @Test
        public void testQueryForObject() {
            String sql = "SELECT COUNT(id) FROM emp";
            Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
            System.out.println(count);
        }
    }
    /*output:打印日志信息+测试类中测试方法执行输出结果
    Jul 09, 2021 11:34:00 PM com.alibaba.druid.pool.DruidDataSource info
    INFO: {dataSource-1} inited
    15
    */
    
posted @   Ramentherapy  阅读(366)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示