连接mysql
    uesr:root
    password:root

    1. package com.exzample.jdbc1;
    2. import java.io.IOException;
    3. import java.io.InputStream;
    4. import java.sql.Connection;
    5. import java.sql.Driver;
    6. import java.sql.DriverManager;
    7. import java.sql.SQLException;
    8. import java.util.Properties;
    9. import org.junit.Test;
    10. public class ConnectionTest {
    11. // 方式一:
    12. @Test
    13. public void testConnection1() throws SQLException {
    14. // 获取Driver实现类对象
    15. Driver driver = new com.mysql.cj.jdbc.Driver();
    16. // url:http://localhost:8080/gmall/keyboard.jpg
    17. // jdbc:mysql:协议
    18. // localhost:ip地址
    19. // 3306:默认mysql的端口号
    20. // test:test数据库
    21. String url = "jdbc:mysql://localhost:3306/test";
    22. // 将用户名和密码封装在Properties中
    23. Properties info = new Properties();
    24. info.setProperty("user", "root");
    25. info.setProperty("password", "root");
    26. Connection conn = driver.connect(url, info);
    27. System.out.println(conn);
    28. }
    29. // 方式二:对方式一的迭代:在如下的程序中不出现第三方的api,使得程序具有更好的可移植性
    30. @Test
    31. public void testConnection2() throws Exception {
    32. // 1.获取Driver实现类对象:使用反射
    33. Class clazz = Class.forName("com.mysql.cj.jdbc.Driver");
    34. Driver driver = (Driver) clazz.newInstance();
    35. // 2.提供要连接的数据库
    36. String url = "jdbc:mysql://localhost:3306/test";
    37. // 3.提供连接需要的用户名和密码
    38. Properties info = new Properties();
    39. info.setProperty("user", "root");
    40. info.setProperty("password", "root");
    41. // 4.获取连接
    42. Connection conn = driver.connect(url, info);
    43. System.out.println(conn);
    44. }
    45. // 方式三:使用DriverManager替换Driver
    46. @Test
    47. public void testConnection3() throws Exception {
    48. // 1.获取Driver实现类的对象
    49. Class clazz = Class.forName("com.mysql.cj.jdbc.Driver");
    50. Driver driver = (Driver) clazz.newInstance();
    51. // 2.提供另外三个连接的基本信息:
    52. String url = "jdbc:mysql://localhost:3306/test";
    53. String user = "root";
    54. String password = "root";
    55. // 注册驱动
    56. DriverManager.registerDriver(driver);
    57. // 获取连接
    58. Connection conn = DriverManager.getConnection(url, user, password);
    59. System.out.println(conn);
    60. }
    61. // 方式四:可以只是加载驱动,不用显示的注册驱动过了。
    62. @Test
    63. public void testConnection4() throws Exception {
    64. // 1.提供三个连接的基本信息:
    65. String url = "jdbc:mysql://localhost:3306/test";
    66. String user = "root";
    67. String password = "root";
    68. // 2.加载Driver
    69. Class.forName("com.mysql.cj.jdbc.Driver");
    70. //相较于方式三,可以省略如下的操作:
    71. // Driver driver = (Driver) clazz.newInstance();
    72. // // 注册驱动
    73. // DriverManager.registerDriver(driver);
    74. //为什么可以省略上述操作呢?
    75. /*
    76. * 在mysql的Driver实现类中,声明了如下的操作:
    77. * static {
    78. try {
    79. java.sql.DriverManager.registerDriver(new Driver());
    80. } catch (SQLException E) {
    81. throw new RuntimeException("Can't register driver!");
    82. }
    83. }
    84. */
    85. // 3.获取连接
    86. Connection conn = DriverManager.getConnection(url, user, password);
    87. System.out.println(conn);
    88. }
    89. //方式五(final版):将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接
    90. /*
    91. * 此种方式的好处?
    92. * 1.实现了数据与代码的分离。实现了解耦
    93. * 2.如果需要修改配置文件信息,可以避免程序重新打包。
    94. */
    95. @Test
    96. public void getConnection5() throws Exception{
    97. //1.读取配置文件中的4个基本信息
    98. InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
    99. Properties pros = new Properties();
    100. pros.load(is);
    101. String user = pros.getProperty("user");
    102. String password = pros.getProperty("password");
    103. String url = pros.getProperty("url");
    104. String driverClass = pros.getProperty("driverClass");
    105. //2.加载驱动
    106. Class.forName(driverClass);
    107. //3.获取连接
    108. Connection conn = DriverManager.getConnection(url, user, password);
    109. System.out.println(conn);
    110. }
    111. }

    配置文件

    1. user=root
    2. password=root
    3. url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
    4. driverClass=com.mysql.cj.jdbc.Driver

    PreparedStatement
    概念:
    3.3 PreparedStatement的使用
    3.3.1 PreparedStatement介绍
    可以通过调用 Connection 对象的 preparedStatement(String sql) 方法获取 PreparedStatement 对象
    PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
    PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的
    setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1
    开始),第二个是设置的 SQL 语句中的参数的值
    3.3.2 PreparedStatement vs Statement
    代码的可读性和可维护性。
    PreparedStatement 能最大可能提高性能:
    DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的
    编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参
    数直接传入编译过的语句执行代码中就会得到执行。
    在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意
    义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。
    (语法检查,语义检查,翻译成二进制命令,缓存)
    PreparedStatement 可以防止 SQL 注入
    3.4 ResultSet与ResultSetMetaData
    3.4.1 ResultSet
    查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象
    ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现
    ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。
    ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象
    的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。
    相当于Iterator对象的 hasNext() 和 next() 方法的结合体。
    当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。
    例如: getInt(1), getString(“name”)
    注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。
    ResultSet 接口的常用方法:
    boolean next()
    getString()

    image.png
    3.4.2 ResultSetMetaData
    可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
    ResultSetMetaData meta = rs.getMetaData();
    getColumnName(int column):获取指定列的名称
    getColumnLabel(int column):获取指定列的别名
    getColumnCount():返回当前 ResultSet 对象中的列数。
    getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
    getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
    isNullable(int column):指示指定列中的值是否可以为 null。
    isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的
    image.png
    3.5 资源的释放
    释放ResultSet, Statement,Connection。
    数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将
    导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
    可以在finally中关闭,保证及时其他代码出现异常,资源也一定能被关闭。
    3.6 JDBC API小结
    两种思想
    面向接口编程的思想
    ORM思想(object relational mapping)
    一个数据表对应一个java类
    表中的一条记录对应java类的一个对象
    表中的一个字段对应java类的一个属性
    sql是需要结合列名和表的属性名来写。注意起别名。
    两种技术
    JDBC结果集的元数据:ResultSetMetaData
    获取列数:getColumnCount()
    获取列的别名:getColumnLabel()
    通过反射,创建指定类的对象,获取指定的属性并赋值
    throws

    1. package com.exzample.jdbc1;
    2. import java.io.InputStream;
    3. import java.sql.Connection;
    4. import java.sql.DriverManager;
    5. import java.text.SimpleDateFormat;
    6. import java.util.Date;
    7. import java.util.Properties;
    8. import java.util.logging.SimpleFormatter;
    9. public class PreparedStatement {
    10. public void update() throws Exception{
    11. //1.读取配置文件中的4个基本信息
    12. InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
    13. Properties pros = new Properties();
    14. pros.load(is);
    15. String user = pros.getProperty("user");
    16. String password = pros.getProperty("password");
    17. String url = pros.getProperty("url");
    18. String driverClass = pros.getProperty("driverClass");
    19. //2.加载驱动
    20. Class.forName(driverClass);
    21. //3.获取连接
    22. Connection conn = DriverManager.getConnection(url, user, password);
    23. System.out.println(conn);
    24. //4.预编译sql语句,返回PreparedStatement实例
    25. String sql = "insert into customers(name,email,birth)value(?,?,?)";
    26. java.sql.PreparedStatement ps = conn.prepareStatement(sql);
    27. //5.填充占位符(?)
    28. ps.setString(1,"娜美");
    29. ps.setString(2,"134@qq.com");
    30. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    31. Date date = simpleDateFormat.parse("1234-02-03");
    32. ps.setDate(3,new java.sql.Date(date.getTime()));
    33. //6.执行操作
    34. ps.execute();
    35. //7.关闭连接
    36. ps.close();
    37. conn.close();
    38. }
    39. }

    try-catch
    快捷键ctrl-alt-t

    1. package com.exzample.jdbc1;
    2. import java.io.IOException;
    3. import java.io.InputStream;
    4. import java.sql.Connection;
    5. import java.sql.DriverManager;
    6. import java.sql.SQLException;
    7. import java.text.ParseException;
    8. import java.text.SimpleDateFormat;
    9. import java.util.Date;
    10. import java.util.Properties;
    11. import java.util.logging.SimpleFormatter;
    12. public class PreparedStatement {
    13. public void update(){
    14. Connection conn = null;
    15. java.sql.PreparedStatement ps = null;
    16. try {
    17. //1.读取配置文件中的4个基本信息
    18. InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
    19. Properties pros = new Properties();
    20. pros.load(is);
    21. String user = pros.getProperty("user");
    22. String password = pros.getProperty("password");
    23. String url = pros.getProperty("url");
    24. String driverClass = pros.getProperty("driverClass");
    25. //2.加载驱动
    26. Class.forName(driverClass);
    27. //3.获取连接
    28. conn = DriverManager.getConnection(url, user, password);
    29. // System.out.println(conn);
    30. //4.预编译sql语句,返回PreparedStatement实例
    31. String sql = "insert into customers(name,email,birth)value(?,?,?)";
    32. ps = conn.prepareStatement(sql);
    33. //5.填充占位符(?)
    34. ps.setString(1,"娜美");
    35. ps.setString(2,"134@qq.com");
    36. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    37. Date date = simpleDateFormat.parse("1234-02-03");
    38. ps.setDate(3,new java.sql.Date(date.getTime()));
    39. //6.执行操作
    40. ps.execute();
    41. } catch (IOException e) {
    42. e.printStackTrace();
    43. } catch (ClassNotFoundException e) {
    44. e.printStackTrace();
    45. } catch (SQLException throwables) {
    46. throwables.printStackTrace();
    47. } catch (ParseException e) {
    48. e.printStackTrace();
    49. }finally {
    50. //7.关闭连接
    51. try {
    52. if (ps!=null)
    53. ps.close();
    54. } catch (SQLException throwables) {
    55. throwables.printStackTrace();
    56. }
    57. try {
    58. if (conn!=null)
    59. conn.close();
    60. } catch (SQLException throwables) {
    61. throwables.printStackTrace();
    62. }
    63. }
    64. }
    65. }

    JDBCutil工具类

    1. package com.exzample.jdbc1;
    2. import java.io.InputStream;
    3. import java.sql.Connection;
    4. import java.sql.DriverManager;
    5. import java.sql.PreparedStatement;
    6. import java.sql.SQLException;
    7. import java.util.Properties;
    8. /*
    9. JDBC工具类
    10. */
    11. public class JDBCUtil {
    12. public static Connection getConnetion()throws Exception{
    13. //1.读取配置文件中的4个基本信息
    14. InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");//类加载器
    15. Properties pros = new Properties();
    16. pros.load(is);
    17. String user = pros.getProperty("user");
    18. String password = pros.getProperty("password");
    19. String url = pros.getProperty("url");
    20. String driverClass = pros.getProperty("driverClass");
    21. //2.加载驱动
    22. Class.forName(driverClass);
    23. //3.获取连接
    24. Connection conn = DriverManager.getConnection(url, user, password);
    25. return conn;
    26. }
    27. public static void closeConnection(Connection conn, PreparedStatement ps){
    28. try {
    29. if (ps!=null)
    30. ps.close();
    31. } catch (SQLException throwables) {
    32. throwables.printStackTrace();
    33. }
    34. try {
    35. if (conn!=null)
    36. conn.close();
    37. } catch (SQLException throwables) {
    38. throwables.printStackTrace();
    39. }
    40. }
    41. }

    image.png
    使用PreparedStatement实现增删改通用代码

    1. //通用的增、删、改操作(体现一:增、删、改 ; 体现二:针对于不同的表)
    2. public void update(String sql,Object ... args){
    3. Connection conn = null;
    4. PreparedStatement ps = null;
    5. try {
    6. //1.获取数据库的连接
    7. conn = JDBCUtils.getConnection();
    8. //2.获取PreparedStatement的实例 (或:预编译sql语句)
    9. ps = conn.prepareStatement(sql);
    10. //3.填充占位符
    11. for(int i = 0;i < args.length;i++){
    12. ps.setObject(i + 1, args[i]);
    13. }
    14. //4.执行sql语句
    15. ps.execute();
    16. } catch (Exception e) {
    17. e.printStackTrace();
    18. }finally{
    19. //5.关闭资源
    20. JDBCUtils.closeResource(conn, ps);
    21. }
    22. }

    image.png
    使用PreparedStatement实现查询功能
    image.png
    ORM编程思想
    image.png
    CustomerBeen:
    image.png
    OrderBeen:

    1. package com.exzample;
    2. //
    3. // Source code recreated from a .class file by IntelliJ IDEA
    4. // (powered by FernFlower decompiler)
    5. //
    6. import java.sql.Date;
    7. public class Order {
    8. private int orderId;
    9. private String orderName;
    10. private Date orderDate;
    11. public Order() {
    12. }
    13. public Order(int orderId, String orderName, Date orderDate) {
    14. this.orderId = orderId;
    15. this.orderName = orderName;
    16. this.orderDate = orderDate;
    17. }
    18. public int getOrderId() {
    19. return this.orderId;
    20. }
    21. public void setOrderId(int orderId) {
    22. this.orderId = orderId;
    23. }
    24. public String getOrderName() {
    25. return this.orderName;
    26. }
    27. public void setOrderName(String orderName) {
    28. this.orderName = orderName;
    29. }
    30. public Date getOrderDate() {
    31. return this.orderDate;
    32. }
    33. public void setOrderDate(Date orderDate) {
    34. this.orderDate = orderDate;
    35. }
    36. public String toString() {
    37. return "Order [orderId=" + this.orderId + ", orderName=" + this.orderName + ", orderDate=" + this.orderDate + "]";
    38. }
    39. }

    queryForCustomers or Order通用代码:

    1. package com.exzample.jdbc1;
    2. import com.exzample.Customer;
    3. import org.junit.Test;
    4. import java.lang.reflect.Field;
    5. import java.sql.Connection;
    6. import java.sql.PreparedStatement;
    7. import java.sql.ResultSet;
    8. import java.sql.ResultSetMetaData;
    9. public class SelectORM {
    10. @Test
    11. public void testqueryForCustomers(){
    12. String sql = "select id,name,birth,email from customers where id = ?";
    13. Customer customer = queryForCustomers(sql, 1);
    14. System.out.println(customer);
    15. }
    16. public Customer queryForCustomers(String sql, Object...args){
    17. Connection conn = null;
    18. PreparedStatement ps = null;
    19. ResultSet resultSet = null;
    20. try {
    21. // 1.获取数据库连接
    22. conn = JDBCUtil.getConnetion();
    23. // 2.预编译sql语句,得到PreparedStatement对象
    24. ps = conn.prepareStatement(sql);
    25. // 3.填充占位符
    26. for (int i = 0;i<args.length;i++){
    27. ps.setObject(i+1,args[i]);
    28. }
    29. // 4.执行executeQuery(),得到结果集:ResultSet
    30. resultSet = ps.executeQuery();
    31. // 5.得到结果集的元数据:ResultSetMetaData
    32. ResultSetMetaData rsmd = resultSet.getMetaData();
    33. // 6.1通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值
    34. int columnCount = rsmd.getColumnCount();
    35. if (resultSet.next()){
    36. Customer customer = new Customer();
    37. for (int i = 0;i<columnCount;i++){// 遍历每一个列
    38. // 获取列值
    39. Object columValue = resultSet.getObject(i + 1);
    40. //获取每个列的列名
    41. String columnName = rsmd.getColumnName(i + 1);
    42. //给customer对象指定的某个属性,赋值为value,赋值为columValue
    43. Field field = Customer.class.getDeclaredField(columnName);
    44. field.setAccessible(true);
    45. field.set(customer,columValue);
    46. }
    47. return customer;
    48. }
    49. } catch (Exception e) {
    50. e.printStackTrace();
    51. } finally {
    52. JDBCUtil.closeConnection(conn,ps,resultSet);
    53. }
    54. return null;
    55. }
    56. @Test
    57. public void testOrderForQuery() {
    58. String sql = "select order_id orderId,order_name orderName,order_date orderDate from `order` where order_id = ?";
    59. Order order = this.orderForQuery(sql, 1);
    60. System.out.println(order);
    61. }
    62. public Order orderForQuery(String sql, Object... args) {
    63. Connection conn = null;
    64. PreparedStatement ps = null;
    65. ResultSet rs = null;
    66. try {
    67. conn = JDBCUtil.getConnetion();
    68. ps = conn.prepareStatement(sql);
    69. for(int i = 0; i < args.length; ++i) {
    70. ps.setObject(i + 1, args[i]);
    71. }
    72. rs = ps.executeQuery();
    73. ResultSetMetaData rsmd = rs.getMetaData();
    74. int columnCount = rsmd.getColumnCount();
    75. if (rs.next()) {
    76. Order order = new Order();
    77. for(int i = 0; i < columnCount; ++i) {
    78. Object columnValue = rs.getObject(i + 1);
    79. String columnLabel = rsmd.getColumnLabel(i + 1);
    80. Field field = Order.class.getDeclaredField(columnLabel);
    81. field.setAccessible(true);
    82. field.set(order, columnValue);
    83. }
    84. return order;
    85. }
    86. } catch (Exception var17) {
    87. var17.printStackTrace();
    88. } finally {
    89. JDBCUtil.closeConnection(conn, ps, rs);
    90. }
    91. return null;
    92. }
    93. }

    Test结果:
    image.png
    image.png
    拓展:PreparedStatement针对不同表的的通用查询(返回一条记录or多条记录)

    1. package com.atguigu3.preparedstatement.crud;
    2. import com.atguigu3.bean.Customer;
    3. import com.atguigu3.bean.Order;
    4. import com.atguigu3.util.JDBCUtils;
    5. import java.lang.reflect.Field;
    6. import java.sql.Connection;
    7. import java.sql.PreparedStatement;
    8. import java.sql.ResultSet;
    9. import java.sql.ResultSetMetaData;
    10. import java.util.ArrayList;
    11. import java.util.List;
    12. import org.junit.Test;
    13. public class PreparedStatementQueryTest {
    14. public PreparedStatementQueryTest() {
    15. }
    16. @Test
    17. public void testGetForList() {
    18. String sql = "select id,name,email from customers where id < ?";
    19. List<Customer> list = this.getForList(Customer.class, sql, 12);
    20. list.forEach(System.out::println);
    21. String sql1 = "select order_id orderId,order_name orderName from `order`";
    22. List<Order> orderList = this.getForList(Order.class, sql1);
    23. orderList.forEach(System.out::println);
    24. }
    25. public <T> List<T> getForList(Class<T> clazz, String sql, Object... args) {
    26. Connection conn = null;
    27. PreparedStatement ps = null;
    28. ResultSet rs = null;
    29. try {
    30. conn = JDBCUtils.getConnection();
    31. ps = conn.prepareStatement(sql);
    32. for(int i = 0; i < args.length; ++i) {
    33. ps.setObject(i + 1, args[i]);
    34. }
    35. rs = ps.executeQuery();
    36. ResultSetMetaData rsmd = rs.getMetaData();
    37. int columnCount = rsmd.getColumnCount();
    38. ArrayList list = new ArrayList();
    39. while(rs.next()) {
    40. T t = clazz.newInstance();
    41. for(int i = 0; i < columnCount; ++i) {
    42. Object columValue = rs.getObject(i + 1);
    43. String columnLabel = rsmd.getColumnLabel(i + 1);
    44. Field field = clazz.getDeclaredField(columnLabel);
    45. field.setAccessible(true);
    46. field.set(t, columValue);
    47. }
    48. list.add(t);
    49. }
    50. return list;
    51. } catch (Exception e) {
    52. e.printStackTrace();
    53. } finally {
    54. JDBCUtils.closeResource(conn, ps, rs);
    55. }
    56. return null;
    57. }
    58. @Test
    59. public void testGetInstance() {
    60. String sql = "select id,name,email from customers where id = ?";
    61. Customer customer = (Customer)this.getInstance(Customer.class, sql, 12);
    62. System.out.println(customer);
    63. String sql1 = "select order_id orderId,order_name orderName from `order` where order_id = ?";
    64. Order order = (Order)this.getInstance(Order.class, sql1, 1);
    65. System.out.println(order);
    66. }
    67. public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
    68. Connection conn = null;
    69. PreparedStatement ps = null;
    70. ResultSet rs = null;
    71. try {
    72. conn = JDBCUtils.getConnection();
    73. ps = conn.prepareStatement(sql);
    74. for(int i = 0; i < args.length; ++i) {
    75. ps.setObject(i + 1, args[i]);
    76. }
    77. rs = ps.executeQuery();
    78. ResultSetMetaData rsmd = rs.getMetaData();
    79. int columnCount = rsmd.getColumnCount();
    80. if (rs.next()) {
    81. T t = clazz.newInstance();
    82. for(int i = 0; i < columnCount; ++i) {
    83. Object columValue = rs.getObject(i + 1);
    84. String columnLabel = rsmd.getColumnLabel(i + 1);
    85. Field field = clazz.getDeclaredField(columnLabel);
    86. field.setAccessible(true);
    87. field.set(t, columValue);
    88. }
    89. return t;
    90. }
    91. } catch (Exception e) {
    92. e.printStackTrace();
    93. } finally {
    94. JDBCUtils.closeResource(conn, ps, rs);
    95. }
    96. return null;
    97. }
    98. }

    PreparedStatement解决sql注入问题:

    1. package com.atguigu2.statement.crud;
    2. import com.atguigu3.util.JDBCUtils;
    3. import java.lang.reflect.Field;
    4. import java.sql.Connection;
    5. import java.sql.PreparedStatement;
    6. import java.sql.ResultSet;
    7. import java.sql.ResultSetMetaData;
    8. import java.util.Scanner;
    9. import org.junit.Test;
    10. public class PreparedStatementTest {
    11. public PreparedStatementTest() {
    12. }
    13. @Test
    14. public void testLogin() {
    15. Scanner scanner = new Scanner(System.in);
    16. System.out.print("请输入用户名:");
    17. String user = scanner.nextLine();
    18. System.out.print("请输入密码:");
    19. String password = scanner.nextLine();
    20. String sql = "SELECT user,password FROM user_table WHERE user = ? and password = ?";
    21. User returnUser = (User)this.getInstance(User.class, sql, user, password);
    22. if (returnUser != null) {
    23. System.out.println("登录成功");
    24. } else {
    25. System.out.println("用户名不存在或密码错误");
    26. }
    27. }
    28. public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
    29. Connection conn = null;
    30. PreparedStatement ps = null;
    31. ResultSet rs = null;
    32. try {
    33. conn = JDBCUtils.getConnection();
    34. ps = conn.prepareStatement(sql);
    35. for(int i = 0; i < args.length; ++i) {
    36. ps.setObject(i + 1, args[i]);
    37. }
    38. rs = ps.executeQuery();
    39. ResultSetMetaData rsmd = rs.getMetaData();
    40. int columnCount = rsmd.getColumnCount();
    41. if (rs.next()) {
    42. T t = clazz.newInstance();
    43. for(int i = 0; i < columnCount; ++i) {
    44. Object columValue = rs.getObject(i + 1);
    45. String columnLabel = rsmd.getColumnLabel(i + 1);
    46. Field field = clazz.getDeclaredField(columnLabel);
    47. field.setAccessible(true);
    48. field.set(t, columValue);
    49. }
    50. return t;
    51. }
    52. } catch (Exception e) {
    53. e.printStackTrace();
    54. } finally {
    55. JDBCUtils.closeResource(conn, ps, rs);
    56. }
    57. return null;
    58. }
    59. }

    exer1

    1. public class Exer1Test {
    2. @Test
    3. public void testInsert(){
    4. Scanner scanner = new Scanner(System.in);
    5. System.out.print("请输入用户名:");
    6. String name = scanner.next();
    7. System.out.print("请输入邮箱:");
    8. String email = scanner.next();
    9. System.out.print("请输入生日:");
    10. String birthday = scanner.next();//'1992-09-08'
    11. String sql = "insert into customers(name,email,birth)values(?,?,?)";
    12. int insertCount = update(sql,name,email,birthday);
    13. if(insertCount > 0){
    14. System.out.println("添加成功");
    15. }else{
    16. System.out.println("添加失败");
    17. }
    18. }
    19. // 通用的增删改操作
    20. public int update(String sql, Object... args) {// sql中占位符的个数与可变形参的长度相同!
    21. Connection conn = null;
    22. PreparedStatement ps = null;
    23. try {
    24. // 1.获取数据库的连接
    25. conn = JDBCUtils.getConnection();
    26. // 2.预编译sql语句,返回PreparedStatement的实例
    27. ps = conn.prepareStatement(sql);
    28. // 3.填充占位符
    29. for (int i = 0; i < args.length; i++) {
    30. ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
    31. }
    32. // 4.执行
    33. /*
    34. * ps.execute():
    35. * 如果执行的是查询操作,有返回结果,则此方法返回true;
    36. * 如果执行的是增、删、改操作,没有返回结果,则此方法返回false.
    37. */
    38. //方式一:
    39. // return ps.execute();
    40. //方式二:
    41. return ps.executeUpdate();
    42. } catch (Exception e) {
    43. e.printStackTrace();
    44. } finally {
    45. // 5.资源的关闭
    46. JDBCUtils.closeResource(conn, ps);
    47. }
    48. return 0;
    49. }
    50. }

    exer2

    1. public class Exer2Test {
    2. public Exer2Test() {
    3. }
    4. @Test
    5. public void testInsert() {
    6. Scanner scanner = new Scanner(System.in);
    7. System.out.print("四级/六级:");
    8. int type = scanner.nextInt();
    9. System.out.print("身份证号:");
    10. String IDCard = scanner.next();
    11. System.out.print("准考证号:");
    12. String examCard = scanner.next();
    13. System.out.print("学生姓名:");
    14. String studentName = scanner.next();
    15. System.out.print("所在城市:");
    16. String location = scanner.next();
    17. System.out.print("考试成绩:");
    18. int grade = scanner.nextInt();
    19. String sql = "insert into examstudent(type,IDCard,examCard,studentName,location,grade)values(?,?,?,?,?,?)";
    20. int insertCount = this.update(sql, type, IDCard, examCard, studentName, location, grade);
    21. if (insertCount > 0) {
    22. System.out.println("添加成功");
    23. } else {
    24. System.out.println("添加失败");
    25. }
    26. }
    27. public int update(String sql, Object... args) {
    28. Connection conn = null;
    29. PreparedStatement ps = null;
    30. try {
    31. conn = JDBCUtils.getConnection();
    32. ps = conn.prepareStatement(sql);
    33. for(int i = 0; i < args.length; ++i) {
    34. ps.setObject(i + 1, args[i]);
    35. }
    36. int var7 = ps.executeUpdate();
    37. return var7;
    38. } catch (Exception var10) {
    39. var10.printStackTrace();
    40. } finally {
    41. JDBCUtils.closeResource(conn, ps);
    42. }
    43. return 0;
    44. }
    45. @Test
    46. public void queryWithIDCardOrExamCard() {
    47. System.out.println("请选择您要输入的类型:");
    48. System.out.println("a.准考证号");
    49. System.out.println("b.身份证号");
    50. Scanner scanner = new Scanner(System.in);
    51. String selection = scanner.next();
    52. String IDCard;
    53. String sql;
    54. Student student;
    55. if ("a".equalsIgnoreCase(selection)) {
    56. System.out.println("请输入准考证号:");
    57. IDCard = scanner.next();
    58. sql = "select FlowID flowID,Type type,IDCard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where examCard = ?";
    59. student = (Student)this.getInstance(Student.class, sql, IDCard);
    60. if (student != null) {
    61. System.out.println(student);
    62. } else {
    63. System.out.println("输入的准考证号有误!");
    64. }
    65. } else if ("b".equalsIgnoreCase(selection)) {
    66. System.out.println("请输入身份证号:");
    67. IDCard = scanner.next();
    68. sql = "select FlowID flowID,Type type,IDCard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where IDCard = ?";
    69. student = (Student)this.getInstance(Student.class, sql, IDCard);
    70. if (student != null) {
    71. System.out.println(student);
    72. } else {
    73. System.out.println("输入的身份证号有误!");
    74. }
    75. } else {
    76. System.out.println("您的输入有误,请重新进入程序。");
    77. }
    78. }
    79. public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
    80. Connection conn = null;
    81. PreparedStatement ps = null;
    82. ResultSet rs = null;
    83. try {
    84. conn = JDBCUtils.getConnection();
    85. ps = conn.prepareStatement(sql);
    86. for(int i = 0; i < args.length; ++i) {
    87. ps.setObject(i + 1, args[i]);
    88. }
    89. rs = ps.executeQuery();
    90. ResultSetMetaData rsmd = rs.getMetaData();
    91. int columnCount = rsmd.getColumnCount();
    92. if (rs.next()) {
    93. T t = clazz.newInstance();
    94. for(int i = 0; i < columnCount; ++i) {
    95. Object columValue = rs.getObject(i + 1);
    96. String columnLabel = rsmd.getColumnLabel(i + 1);
    97. Field field = clazz.getDeclaredField(columnLabel);
    98. field.setAccessible(true);
    99. field.set(t, columValue);
    100. }
    101. return t;
    102. }
    103. } catch (Exception var18) {
    104. var18.printStackTrace();
    105. } finally {
    106. JDBCUtils.closeResource(conn, ps, rs);
    107. }
    108. return null;
    109. }
    110. @Test
    111. public void testDeleteByExamCard() {
    112. System.out.println("请输入学生的考号:");
    113. Scanner scanner = new Scanner(System.in);
    114. String examCard = scanner.next();
    115. String sql = "select FlowID flowID,Type type,IDCard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where examCard = ?";
    116. Student student = (Student)this.getInstance(Student.class, sql, examCard);
    117. if (student == null) {
    118. System.out.println("查无此人,请重新输入");
    119. } else {
    120. String sql1 = "delete from examstudent where examCard = ?";
    121. int deleteCount = this.update(sql1, examCard);
    122. if (deleteCount > 0) {
    123. System.out.println("删除成功");
    124. }
    125. }
    126. }
    127. @Test
    128. public void testDeleteByExamCard1() {
    129. System.out.println("请输入学生的考号:");
    130. Scanner scanner = new Scanner(System.in);
    131. String examCard = scanner.next();
    132. String sql = "delete from examstudent where examCard = ?";
    133. int deleteCount = this.update(sql, examCard);
    134. if (deleteCount > 0) {
    135. System.out.println("删除成功");
    136. } else {
    137. System.out.println("查无此人,请重新输入");
    138. }
    139. }
    140. }

    PreparedStatement vs Statement两大优点体现:
    4.1 MySQL BLOB类型
    MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
    插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的。
    MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)
    image.png
    实际使用中根据需要存入的数据大小定义不同的BLOB类型。
    需要注意的是:如果存储的文件过大,数据库的性能会下降。如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如
    下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。

    1. /**
    2. *
    3. * @Description 测试使用PreparedStatement操作Blob类型的数据
    4. * @author shkstart Email:shkstart@126.com
    5. * @version
    6. * @date 下午4:08:58
    7. *
    8. */
    9. public class BlobTest {
    10. //向数据表customers中插入Blob类型的字段
    11. @Test
    12. public void testInsert() throws Exception{
    13. Connection conn = JDBCUtils.getConnection();
    14. String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";
    15. PreparedStatement ps = conn.prepareStatement(sql);
    16. ps.setObject(1,"袁浩");
    17. ps.setObject(2, "yuan@qq.com");
    18. ps.setObject(3,"1992-09-08");
    19. FileInputStream is = new FileInputStream(new File("girl.jpg"));
    20. ps.setBlob(4, is);
    21. ps.execute();
    22. JDBCUtils.closeResource(conn, ps);
    23. }
    24. //查询数据表customers中Blob类型的字段
    25. @Test
    26. public void testQuery(){
    27. Connection conn = null;
    28. PreparedStatement ps = null;
    29. InputStream is = null;
    30. FileOutputStream fos = null;
    31. ResultSet rs = null;
    32. try {
    33. conn = JDBCUtils.getConnection();
    34. String sql = "select id,name,email,birth,photo from customers where id = ?";
    35. ps = conn.prepareStatement(sql);
    36. ps.setInt(1, 21);
    37. rs = ps.executeQuery();
    38. if(rs.next()){
    39. // 方式一:
    40. // int id = rs.getInt(1);
    41. // String name = rs.getString(2);
    42. // String email = rs.getString(3);
    43. // Date birth = rs.getDate(4);
    44. //方式二:
    45. int id = rs.getInt("id");
    46. String name = rs.getString("name");
    47. String email = rs.getString("email");
    48. Date birth = rs.getDate("birth");
    49. Customer cust = new Customer(id, name, email, birth);
    50. System.out.println(cust);
    51. //将Blob类型的字段下载下来,以文件的方式保存在本地
    52. Blob photo = rs.getBlob("photo");
    53. is = photo.getBinaryStream();
    54. fos = new FileOutputStream("zhangyuhao.jpg");
    55. byte[] buffer = new byte[1024];
    56. int len;
    57. while((len = is.read(buffer)) != -1){
    58. fos.write(buffer, 0, len);
    59. }
    60. }
    61. } catch (Exception e) {
    62. e.printStackTrace();
    63. }finally{
    64. try {
    65. if(is != null)
    66. is.close();
    67. } catch (IOException e) {
    68. e.printStackTrace();
    69. }
    70. try {
    71. if(fos != null)
    72. fos.close();
    73. } catch (IOException e) {
    74. e.printStackTrace();
    75. }
    76. JDBCUtils.closeResource(conn, ps, rs);
    77. }
    78. }
    79. }

    5.1 批量执行SQL语句
    当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处
    理。通常情况下比单独提交处理更有效率
    JDBC的批量处理语句包括下面三个方法:
    addBatch(String):添加需要批量处理的SQL语句或是参数;
    executeBatch():执行批量处理语句;
    clearBatch():清空缓存的数据
    通常我们会遇到两种批量执行SQL语句的情况:
    多条SQL语句的批量处理;
    一个SQL语句的批量传参;

    1. /*
    2. * 使用PreparedStatement实现批量数据的操作
    3. *
    4. * update、delete本身就具有批量操作的效果。
    5. * 此时的批量操作,主要指的是批量插入。使用PreparedStatement如何实现更高效的批量插入?
    6. *
    7. * 题目:向goods表中插入20000条数据
    8. * CREATE TABLE goods(
    9. id INT PRIMARY KEY AUTO_INCREMENT,
    10. NAME VARCHAR(25)
    11. );
    12. * 方式一:使用Statement
    13. * Connection conn = JDBCUtils.getConnection();
    14. * Statement st = conn.createStatement();
    15. * for(int i = 1;i <= 20000;i++){
    16. * String sql = "insert into goods(name)values('name_" + i + "')";
    17. * st.execute(sql);
    18. * }
    19. *
    20. */
    21. public class InsertTest {
    22. //批量插入的方式二:使用PreparedStatement
    23. @Test
    24. public void testInsert1() {
    25. Connection conn = null;
    26. PreparedStatement ps = null;
    27. try {
    28. long start = System.currentTimeMillis();
    29. conn = JDBCUtils.getConnection();
    30. String sql = "insert into goods(name)values(?)";
    31. ps = conn.prepareStatement(sql);
    32. for(int i = 1;i <= 20000;i++){
    33. ps.setObject(1, "name_" + i);
    34. ps.execute();
    35. }
    36. long end = System.currentTimeMillis();
    37. System.out.println("花费的时间为:" + (end - start));//20000:83065
    38. } catch (Exception e) {
    39. e.printStackTrace();
    40. }finally{
    41. JDBCUtils.closeResource(conn, ps);
    42. }
    43. }
    44. /*
    45. * 批量插入的方式三:
    46. * 1.addBatch()、executeBatch()、clearBatch()
    47. * 2.mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。
    48. * ?rewriteBatchedStatements=true 写在配置文件的url后面
    49. * 3.使用更新的mysql 驱动:mysql-connector-java-5.1.37-bin.jar
    50. */
    51. @Test
    52. public void testInsert2() {
    53. Connection conn = null;
    54. PreparedStatement ps = null;
    55. try {
    56. long start = System.currentTimeMillis();
    57. conn = JDBCUtils.getConnection();
    58. String sql = "insert into goods(name)values(?)";
    59. ps = conn.prepareStatement(sql);
    60. for(int i = 1;i <= 1000000;i++){
    61. ps.setObject(1, "name_" + i);
    62. //1."攒"sql
    63. ps.addBatch();
    64. if(i % 500 == 0){
    65. //2.执行batch
    66. ps.executeBatch();
    67. //3.清空batch
    68. ps.clearBatch();
    69. }
    70. }
    71. long end = System.currentTimeMillis();
    72. System.out.println("花费的时间为:" + (end - start));//20000:83065 -- 565
    73. } catch (Exception e) { //1000000:16086
    74. e.printStackTrace();
    75. }finally{
    76. JDBCUtils.closeResource(conn, ps);
    77. }
    78. }
    79. //批量插入的方式四:设置连接不允许自动提交数据
    80. @Test
    81. public void testInsert3() {
    82. Connection conn = null;
    83. PreparedStatement ps = null;
    84. try {
    85. long start = System.currentTimeMillis();
    86. conn = JDBCUtils.getConnection();
    87. //设置不允许自动提交数据
    88. conn.setAutoCommit(false);
    89. String sql = "insert into goods(name)values(?)";
    90. ps = conn.prepareStatement(sql);
    91. for(int i = 1;i <= 1000000;i++){
    92. ps.setObject(1, "name_" + i);
    93. //1."攒"sql
    94. ps.addBatch();
    95. if(i % 500 == 0){
    96. //2.执行batch
    97. ps.executeBatch();
    98. //3.清空batch
    99. ps.clearBatch();
    100. }
    101. }
    102. //提交数据
    103. conn.commit();
    104. long end = System.currentTimeMillis();
    105. System.out.println("花费的时间为:" + (end - start));//20000:83065 -- 565
    106. } catch (Exception e) { //1000000:16086 -- 5114
    107. e.printStackTrace();
    108. }finally{
    109. JDBCUtils.closeResource(conn, ps);
    110. }
    111. }
    112. }