1 操作和访问数据库

数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。
在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:
Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
CallableStatement:用于执行 SQL 存储过程image.png

2 使用Statement操作数据表的弊端

通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。
Statement 接口中定义了下列方法用于执行 SQL 语句:
intexcuteUpdate(Stringsql):执行更新操作INSERT、UPDATE、DELETE
ResultSet executeQuery(Stringsql):执行查询操作SELECT
但是使用Statement操作数据表存在弊端:
问题一:存在拼串操作,繁琐
问题二:存在SQL注入问题
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法。
对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。image.png
代码演示:

  1. public class StatementTest {
  2. // 使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题
  3. @Test
  4. public void testLogin() {
  5. Scanner scan = new Scanner(System.in);
  6. System.out.print("用户名:");
  7. String userName = scan.nextLine();
  8. System.out.print("密 码:");
  9. String password = scan.nextLine();
  10. // SELECT user,password FROM user_table WHERE USER = '1' or ' AND PASSWORD = '='1' or '1' = '1';
  11. String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName + "' AND PASSWORD = '" + password
  12. + "'";
  13. User user = get(sql, User.class);
  14. if (user != null) {
  15. System.out.println("登陆成功!");
  16. } else {
  17. System.out.println("用户名或密码错误!");
  18. }
  19. }
  20. // 使用Statement实现对数据表的查询操作
  21. public <T> T get(String sql, Class<T> clazz) {
  22. T t = null;
  23. Connection conn = null;
  24. Statement st = null;
  25. ResultSet rs = null;
  26. try {
  27. // 1.加载配置文件
  28. InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
  29. Properties pros = new Properties();
  30. pros.load(is);
  31. // 2.读取配置信息
  32. String user = pros.getProperty("user");
  33. String password = pros.getProperty("password");
  34. String url = pros.getProperty("url");
  35. String driverClass = pros.getProperty("driverClass");
  36. // 3.加载驱动
  37. Class.forName(driverClass);
  38. // 4.获取连接
  39. conn = DriverManager.getConnection(url, user, password);
  40. st = conn.createStatement();
  41. rs = st.executeQuery(sql);
  42. // 获取结果集的元数据
  43. ResultSetMetaData rsmd = rs.getMetaData();
  44. // 获取结果集的列数
  45. int columnCount = rsmd.getColumnCount();
  46. if (rs.next()) {
  47. t = clazz.newInstance();
  48. for (int i = 0; i < columnCount; i++) {
  49. // //1. 获取列的名称
  50. // String columnName = rsmd.getColumnName(i+1);
  51. // 1. 获取列的别名
  52. String columnName = rsmd.getColumnLabel(i + 1);
  53. // 2. 根据列名获取对应数据表中的数据
  54. Object columnVal = rs.getObject(columnName);
  55. // 3. 将数据表中得到的数据,封装进对象
  56. Field field = clazz.getDeclaredField(columnName);
  57. field.setAccessible(true);
  58. field.set(t, columnVal);
  59. }
  60. return t;
  61. }
  62. } catch (Exception e) {
  63. e.printStackTrace();
  64. } finally {
  65. // 关闭资源
  66. if (rs != null) {
  67. try {
  68. rs.close();
  69. } catch (SQLException e) {
  70. e.printStackTrace();
  71. }
  72. }
  73. if (st != null) {
  74. try {
  75. st.close();
  76. } catch (SQLException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. if (conn != null) {
  81. try {
  82. conn.close();
  83. } catch (SQLException e) {
  84. e.printStackTrace();
  85. }
  86. }
  87. }
  88. return null;
  89. }