JDBC(复习)

JDBC 连接 🚀 进修 MySQL~(肆)

事务 🚀 进修 MySQL~(伍)

分割线

JUnit

在一个方法上标记 @Test 注解后,这个方法可以脱离 Main 直接运行.

  • 依赖 (一般创建项目时自带)

    1
    2
    3
    4
    5
    6
    <!--单元测试-->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    </dependency>
  • 例子:

    1
    2
    3
    4
    5
    6
    7
    8
    import org.junit.Test;

    public class JDBCTest {
    @Test
    public void test() {
    System.out.println("123");
    }
    }

分割线

SMBMS

项目代码: https://github.com/Weidows/Java/tree/master/JavaWeb/SMBMS

  • 可以拉取代码直接看,下面的笔记着重讲从零开发的流程

  • 我的这个项目应该是跑不起来,在 web,xml 中 filter 那里有个 bug,不过无大碍,知道怎么个原理就好.


搭建

  • Maven-webapp 项目,补全 src/resources,添加依赖,连接 Tomcat 和 MySQL,修改 web.xml 版本

    • 依赖:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      <dependencies>
      <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.1</version>
      <scope>compile</scope>
      </dependency>
      <!-- servlet依赖 -->
      <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
      </dependency>
      <!-- JSP依赖 -->
      <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
      <scope>provided</scope>
      </dependency>
      <!-- JSTL表达式依赖 -->
      <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
      </dependency>
      <!-- Standard标签库 -->
      <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
      </dependency>
      <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>jsp-api</artifactId>
      <version>6.0.13</version>
      </dependency>
      <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
      </dependency>
      <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
      </dependency>
      <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
      <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.23</version>
      </dependency>
      </dependencies>
    • 更改版本号:web.xml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
      version="4.0"
      metadata-complete="true">
      <display-name>Archetype Created Web Application</display-name>

      </web-app>

后端项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|> src/main
|> java/com.weidows
|> dao/mapper // data access object (对应pojo的CRUD类)
|> filter // 过滤器
|> pojo/entity // Plain Ordinary Java Object (ORM映射的实体类,内部一般只有getter和setter)
|> service // 业务类 (操作dao)
|> servlet/controller // servlet后端
|> utils // 工具类
|> bean // spring中 == entity + dao
|> resources // 资源文件

-------

pojo对应数据库中每个记录
-> 在dao中编写操作pojo的SQL/Java代码,实现CRUD的"方法"
-> 在service中通过Java编写事务,并调用dao中CRUD方法实现增删改查"功能"
-> 在servlet就是对应请求和响应来做业务,调用service中的方法.

-------

pojo为最底层,不涉及对象增删操作
-> dao层
-> BaseDao实现创建connection/preparedStatement对象,以及回收connection/preparedStatement/resultSet的方法.
-> 进一步的dao类中进行创建resultSet对象,并回收resultSet/preparedStatement对象
-> 在service层进行connection的关闭,捕获dao层抛出的异常,且此层不再向上抛出异常.
20210424112946

连接配置文件

(resources/db.properties)

1
2
3
4
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/smbms?useSSL=false&useUnicode=true&characterEncoding=utf-8
user=root
password=123456

ORM 映射

(编写 pojo 下的实体类)

初始化 SQL: https://github.com/Weidows/Java/blob/master/JavaWeb/SMBMS/smbms.sql

pojo: https://github.com/Weidows/Java/blob/master/JavaWeb/SMBMS/src/main/java/com/weidows/pojo


静态基本类

https://github.com/Weidows/Java/blob/master/JavaWeb/SMBMS/src/main/java/dao/BaseDao.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package com.weidows.dao;

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

/**
* 操作数据库的基类--静态类
*/
public class BaseDao {

private static final String driver;
private static final String url;
private static final String username;
private static final String password;

private static Connection connection = null;
private static PreparedStatement preparedStatement = null;


//静态代码块,在类加载的时候执行
static {
String configFile = "db.properties";
InputStream inputStream = BaseDao.class.getClassLoader().getResourceAsStream(configFile);
Properties properties = new Properties();
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}


/**
* 获取数据库连接
*
* @return connection
*/
public static Connection getConnection() {
if (connection == null) {
try {
Class.forName(driver);
connection = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
}
return connection;
}

/**
* 查询数据库的公共操作
*
* @param connection
* @param rs
* @param sql
* @param params
* @return
*/
public static ResultSet execute(Connection connection, ResultSet rs, String sql, Object[] params) {
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i + 1, params[i]);
}
rs = preparedStatement.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return rs;
}

/**
* 更新数据库的公共操作
*
* @param connection
* @param sql
* @param params
* @return
* @throws Exception
*/
public static int execute(Connection connection, String sql, Object[] params) {
int updateRows = 0;
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i + 1, params[i]);
}
updateRows = preparedStatement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return updateRows;
}

/**
* 释放资源
*
* @param connection
* @param pstm
* @param rs
* @return
*/
public static boolean closeResource(Connection connection, PreparedStatement pstm, ResultSet rs) {
boolean flag = true;
try {
if (rs != null) {
rs.close();
rs = null;//GC回收
}
if (pstm != null) {
pstm.close();
pstm = null;//GC回收
}
if (connection != null) {
connection.close();
connection = null;//GC回收
}
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
return flag;
}
}

题外话

  • 一个编程书写习惯: 方法中首先把需要用到的变量提出

    就像这里的三个变量,在一开始提出来,就像是类里面的 field,使用起来比较规范,容易排查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public User getLoginUser(Connection connection, String userCode) {
    PreparedStatement pstm = null;
    ResultSet resultSet = null;
    User user = null;
    try {
    if (null != connection) {
    String sql = "select * from smbms_user where userCode=?";
    Object[] params = {userCode};
    resultSet = BaseDao.execute(connection, pstm, resultSet, sql, params);
    if (resultSet.next()) {
    user = setData(resultSet);
    }
    }
    BaseDao.closeResource(null, pstm, resultSet);
    } catch (SQLException throwables) {
    throwables.printStackTrace();
    }
    return user;
    }

分割线

实现登录

  • 在这里复现一下"登录"业务,其他功能以此类推.

    这里着重过程(自上而下),具体怎么实现的业务建议结合源码来学习.

    20210422103020
    20210425232035

分割线

项目总结构

20210426105422