моя контактная информация
Почтамезофия@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
JavaWeb (1: Базовые знания и построение среды)https://blog.csdn.net/xpy2428507302/article/details/140365130?spm=1001.2014.3001.5501JavaWeb (2: сервлет и Jsp, прослушиватель и фильтр)
https://blog.csdn.net/xpy2428507302/article/details/140365159?spm=1001.2014.3001.5501
Оглавление
7. Пул подключений к базе данных
11. Трехуровневая архитектура MVC
2. трехуровневая архитектура mvc
JDBC (Java DataBase Connectivity): технология подключения к базе данных Java.
JDBC — это система управления, независимая от конкретной базы данных, и общедоступный интерфейс для универсального доступа к базе данных SQL и ее операций.
Определяет набор стандартов, обеспечивающих единый способ доступа к различным базам данных.
JDBC — это прикладной API для доступа к базе данных, состоящий из набора классов и интерфейсов, написанных на языке Java.
Включает в себя два уровня:
① Прикладной API для вызова программистов.
② API, ориентированный на базу данных, позволяющий производителям разрабатывать драйверы баз данных.
Чтобы соединить разные базы данных с помощью JDBC, вам нужно всего лишь загрузить разные пакеты драйверов баз данных, и вам не придется беспокоиться о различиях в операционных языках баз данных.
① Создать таблицу базы данных.
- CREATE TABLE users(
- id INT PRIMARY KEY,
- `name` VARCHAR(40),
- `password` VARCHAR(40),
- email VARCHAR(60),
- birthday DATE
- );
- INSERT INTO users(id,`name`,`password`,email,birthday)
- INSERT INTO users(id,`name`,`password`,email,birthday)
- INSERT INTO users(id,`name`,`password`,email,birthday)
- SELECT * FROM users;
② Импорт зависимостей базы данных
- <!--mysql的驱动-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.31</version>
- </dependency>
③ Использование JDBC:
Ⅰ Загрузите драйвер базы данных (мост между Java-программой и базой данных).
Ⅱ Получите соединение, соединение между Java-программой и базой данных.
Ⅲ Создайте объект Statement, который отправляет SQL в базу данных, созданную Connection.
Ⅳ Написание операторов SQL (написание разных SQL в зависимости от бизнеса).
Ⅴ Выполнить SQL (если вы хотите получить возвращаемое значение, создайте объект ResultSet, чтобы сохранить результаты запроса после выполнения оператора).
Ⅵ Закройте соединение.
- public class JDBCTest {
- public static void main(String[] args) throws Exception {
- //配置信息
- //要连接的数据库URL(解决中文乱码问题:useUnicode=true&characterEncoding=utf8&useSSL=true)
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- //连接的数据库时使用的用户名
- String username = "root";
- //连接的数据库时使用的密码
- String password = "123456";
- Connection conn = null;
- Statement st = null;
- ResultSet rs = null;
-
- try {
- //1.加载驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取与数据库的链接
- conn = DriverManager.getConnection(url, username, password);
- //3.获取用于向数据库发送sql语句的statement对象
- st = conn.createStatement();
- String sql = "select id,name,password,email,birthday from users";
- //4.向数据库发sql,并获取代表结果集的resultset对象
- //查:executeQuery 增删改:executeUpdate
- rs = st.executeQuery(sql);
- //5.取出结果集的数据
- while (rs.next()) {
- System.out.println("id=" + rs.getInt("id"));
- System.out.println("name=" + rs.getString("name"));
- System.out.println("password=" + rs.getString("password"));
- System.out.println("email=" + rs.getString("email"));
- System.out.println("birthday=" + rs.getDate("birthday"));
- }
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //6.关闭链接,释放资源(先开后关)
- rs.close();
- st.close();
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- }
jdbc:mysql://localhost:3306/xxx
jdbc | протокол |
mysql | подпротокол |
локальный хост:3306 | хост: порт |
ххх | база данных |
Как написать часто используемые URL-адреса базы данных:
Соединение используется для представления связей с базой данных, а Коллекция является наиболее важным объектом в программировании баз данных.
Все взаимодействия между клиентом и базой данных осуществляются через объект подключения., общие методы этого объекта:
createStatement() | Создайте объект запроса, который отправляет sql в базу данных. |
подготовитьStatement(sql) | Создайте объект Подготовкасатемент, который отправляет предварительно скомпилированный SQL-код в базу данных. |
setAutoCommit(логическое значение autoCommit) | Установите, будут ли транзакции фиксироваться автоматически |
совершить() | Отправьте транзакцию по ссылке |
откат() | Откат транзакции по этой ссылке |
Объект Statement используется для отправки операторов SQL в базу данных. Общие методы объекта Statement:
выполнитьЗапрос(Строка SQL) | Используется для отправки операторов запроса к данным и возврата набора результатов ResultSet. |
executeUpdate(строка sql) | Используется для отправки операторов вставки, обновления или удаления в базу данных и возврата количества строк, обновленных в базе данных. |
выполнить(строка sql) | Используется для отправки произвольных операторов sql в базу данных. |
addBatch(строка sql) | Поместите несколько операторов sql в пакет |
executeBatch() | Отправьте пакет операторов sql в базу данных для выполнения. |
Уведомление:
Для повышения эффективности работы метод выполнения обычно не используется напрямую.
Вместо этого используйте их соответственно: ExecuteQuery для запросов; ExecuteUpdate для добавлений, удалений и изменений.
ResultSet используется для представления результатов выполнения операторов Sql.
Набор результатов При инкапсуляции набора результатов выполнения используйтепохоже на таблицуПуть。
Объект ResultSet поддерживает курсор, указывающий на строки данных таблицы.Изначально курсор находится перед первой строкой。
Вызов метода ResultSet.next() может указать курсор на определенную строку данных и вызвать метод getxxx для получения данных строки.
① Получить любой тип данных
получитьОбъект(целый индекс) | Получите объект Object в соответствии с указанным количеством столбцов. |
getObject(строка columnName) | Получите объект Object в соответствии с указанным именем атрибута. |
② Получить данные указанного типа, например получить тип String.
getString(целый индекс) | Получить объект String на основе указанного количества столбцов. |
getString(String имя_столбца) | Получите объект String в соответствии с указанным именем атрибута. |
③ Как прокручивать набор результатов:
следующий() | перейти на следующую строку |
Предыдущий() | перейти на предыдущую строку |
абсолютный(строка int) | Перейти на указанную строку |
преждеПервого() | Переместить переднюю часть resultSet |
afterLast() | Перейти в конец resultSet |
После завершения работы программы Jdbc не забудьте освободить объекты, созданные программой, для взаимодействия с базой данных во время работающего процесса.
Этими объектами обычно являются объекты ResultSet, Statement и Connection.
Особенно объект Connection, это очень редкий ресурс и его необходимо освободить сразу после использования.
Если соединение не может быть закрыто быстро и правильно, это может легко привести к простою системы.
Чтобы гарантировать возможность выполнения кода выпуска ресурса, код выпуска ресурса также необходимо поместить в операторfinally.
При использовании Statement для разработки возникают две проблемы:
① Строковые строки необходимо часто соединять, а частота ошибок высока.
- String username = "zhangsan";
- String password = "123";
- String sql = "select * from users where name='"+username+"' and password='"+password+"'";
- ResultSet rs = st.executeQuery(sql);
② Существует потенциальный риск SQL-инъекции.
SQL-инъекция: внедрение незаконных операторов SQL в данные, вводимые пользователем, с использованием хитрых методов объединения строк, вызывающих короткое замыкание SQL и тем самым кражу данных базы данных.
- public class SQLTest {
- public static void main(String[] args) throws Exception {
- // 正常登陆sql:select * from users where name='张三' and password ='123456'
- //login("张三","123456");
- // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
- login("", "123456' or '1'='1");
- }
-
- public static void login(String username, String password) throws Exception {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String dbUsername = "root";
- String dbPassword = "123456";
-
- //1.加载驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取与数据库的链接
- Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
- //3.获取用于向数据库发送sql语句的statement
- Statement st = conn.createStatement();
- String sql = "select * from users where name='" + username + "' and password='" + password + "'";
- System.out.println(sql);
- //4.向数据库发sql,并获取代表结果集的rs
- ResultSet rs = st.executeQuery(sql);
- if (rs.next()) {
- System.out.println("登录成功");
- } else {
- System.out.println("登录失败");
- }
- //6.关闭链接,释放资源
- rs.close();
- st.close();
- conn.close();
- }
- }
результат операции:
Уведомление:
Приоритет и в инструкции SQL больше, чем или, поэтому выполняемый SQL эквивалентен выбору * из пользователей, где '1' = '1';
Решение:Используйте ReadedStatement, подкласс Statement, который предоставляет функцию заполнителя SQL.
Нет необходимости объединять строки, а введенные пользователем данные будут полностью обнаружены, что сделает их более безопасными.
- public class PSTest {
- public static void main(String[] args) throws Exception {
- // 正常登陆sql:select * from users where name='张三' and password ='123456'
- //login("张三","123456");
- // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
- login("", "123456' or '1'='1");
- }
-
- public static void login(String username, String password) throws Exception {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String dbUsername = "root";
- String dbPassword = "123456";
-
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
- //获取用于向数据库发送预编译sql语句的prepareStatement
- String sql = "select * from users where name = ? and password = ?";
- System.out.println(sql);
- PreparedStatement ps = conn.prepareStatement(sql);
- //给占位符 ? 填充数据
- ps.setString(1, username);
- ps.setString(2, password);
- ResultSet rs = ps.executeQuery();
- if (rs.next()) {
- System.out.println("登录成功");
- } else {
- System.out.println("登录失败");
- }
- rs.close();
- ps.close();
- conn.close();
- }
- }
результат операции:
Транзакция представляет собой логический набор операций, все из которых либо успешны, либо все неудачны (принцип ACID).
Когда программа Jdbc получает объект Connection из базы данных, по умолчанию объект Connection автоматически отправляет транзакцию в базу данных.
Если вы хотите отключить этот метод отправки по умолчанию и разрешить выполнение нескольких SQL-запросов в одной транзакции, вы можете использовать следующий оператор транзакции управления JDBC.
Connection.setAutoCommit(false); | начать транзакцию |
Откат соединения(); | Откат транзакции |
Connection.commit(); | совершить транзакцию |
① Создать таблицу учетных записей.
- /*创建账户表*/
- CREATE TABLE account(
- id INT PRIMARY KEY AUTO_INCREMENT,
- NAME VARCHAR(40),
- money DECIMAL(9,2)
- );
- /*插入测试数据*/
- insert into account(name,money) values('A',1000);
- insert into account(name,money) values('B',1000);
- insert into account(name,money) values('C',1000);
② Смоделировать бизнес-сценарий в случае успешного перевода.
- //失败后让数据库自动回滚事务
- public class Demo {
- public static void main(String[] args) {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String username = "root";
- String password = "123456";
- Connection conn = null;
- try {
- Class.forName("com.mysql.cj.jdbc.Driver");
- conn = DriverManager.getConnection(url, username, password);
-
- //通知数据库开启事务,false表示开启
- conn.setAutoCommit(false);
-
- String sql1 = "update account set money=money-100 where name = 'A' ";
- conn.prepareStatement(sql1).executeUpdate();
-
- //模拟执行完SQL1之后程序出现了异常而导致后面的SQL无法正常执行,事务也无法正常提交
- int x = 1/0;
-
- String sql2 = "update account set money=money+100 where name = 'B' ";
- conn.prepareStatement(sql2)executeUpdate();
-
- //sql1 和 sql2都顺利执行,就提交事务
- conn.commit();
- System.out.println("成功!!!");
- } catch (Exception e) {
- //出现异常,通知数据库回滚事务
- conn.rollback();
- e.printStackTrace();
- } finally {
- conn.close();
- }
- }
- }
В разных запросах нужно каждый раз подключаться к базе данных и освобождать ресурсы, при этом будет написано много повторяющегося кода.
Инкапсулируйте операции подготовки и освобождения соединения с базой данных в класс инструмента и вызывайте его напрямую при использовании, чтобы избежать написания повторяющегося кода.
- public class JdbcUtil {
- private static Connection connection;
- private static String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- private static String username = "root";
- private static String password = "123456";
-
- //驱动(类)只需要加载一次,放静态代码块即可
- static {
- try {
- //加载数据库驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // 获取数据库连接对象
- public static Connection getConnection() throws SQLException {
- return DriverManager.getConnection(url, username, password);
- }
-
- // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
- public static void release(Connection conn, Statement st, ResultSet rs) {
- try {
- if (rs != null) {
- rs.close();
- }
- if (st != null) {
- st.close();
- }
- if (conn != null) {
- conn.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Случай вызова, например: добавить пользователя
-
- public void add(String name, String password) {
- Connection conn = null;
- PreparedStatement ps = null;
- try {
- conn = JdbcUtil.getConnection();
- String sql = "insert into users(name,password) values(?,?)";
- ps = conn.prepareStatement(sql);
- ps.setString(1, name);
- ps.setString(2, password);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JdbcUtil.release(conn, ps, null);
- }
- }
Процесс разработки JDBC:
Ⅰ Загрузите драйвер базы данных (нужно загрузить только один раз).
Ⅱ Установить соединение с базой данных (Соединение).
Ⅲ Создайте объект Statement, который отправляет SQL в базу данных, созданную Connection.
Ⅳ Написание операторов SQL.
Ⅴ Выполнить SQL (объект Query -> ResultSet получает набор результатов)
Ⅵ Закройте соединение и освободите ресурсы.
Объект подключения к базе данных получается через DriverManager. Каждый раз при его получении необходимо обратиться к базе данных для получения подключения и проверить имя пользователя и пароль.
Пользователям необходимо получать ссылку из базы данных для каждого запроса, а создание подключения к базе данных обычно требует относительно больших ресурсов и занимает много времени.
Каждый раз, когда выполняется оператор SQL, соединение разрывается, что приводит к пустой трате ресурсов, а ресурсы соединения с базой данных не используются повторно.
Если предположить, что веб-сайт посещается 100 000 человек в день, серверу базы данных необходимо создать 100 000 подключений, что является огромной тратой ресурсов базы данных и может легко вызвать переполнение памяти сервера базы данных и расширение машины.
Решение: пул соединений с базой данных.
Основная идея пула соединений с базой данных:
Создайте пул буферов для базы данных и заранее поместите в него определенное количество объектов подключения.
Если вы хотите получить соединение с базой данных, вам нужно всего лишь взять объект из пула буферов.
После использования поместите его обратно в пул буферов для следующего запроса, добившись повторного использования ресурсов без необходимости повторного создания.
Если в пуле соединений с базой данных нет неактивных объектов соединений, новые запросы попадут в очередь ожидания и будут ждать, пока другие потоки разорвут соединение.
Пул соединений с базой данных JDBC реализуется с использованием интерфейса javax.sql.DataSource. DataSource — это интерфейс, официально предоставляемый java.
При его использовании разработчикам не нужно самостоятельно реализовывать интерфейс, и они могут использовать сторонние инструменты.
C3P0 — это широко используемая сторонняя реализация. В реальной разработке C3P0 можно использовать непосредственно для завершения работы пула подключений к базе данных.
Шаги по использованию:
① Импортировать зависимости в pom.xml.
- <dependency>
- <groupId>com.mchange</groupId>
- <artifactId>c3p0</artifactId>
- <version>0.9.5.2</version>
- </dependency>
② Напишите код
- public class DataSourceTest {
- public static void main(String[] args) {
- try {
- //创建C3P0数据库连接池
- ComboPooledDataSource dataSource=new ComboPooledDataSource();
- dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
- dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8");
- dataSource.setUser("root");
- dataSource.setPassword("123456");
- //设置初始化连接个数
- dataSource.setInitialPoolSize(5);
- //设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限)
- dataSource.setMaxPoolSize(20);
- //当连接对象不够时,再次申请的连接对象个数
- dataSource.setAcquireIncrement(5);
- //设置最小连接数(当连接池中剩余2个连接对象时,就去申请 --> 提前做准备)
- dataSource.setMinPoolSize(2);
- Connection conn=dataSource.getConnection();
-
- //SQL操作...
-
- //将连接还回到数据库连接池中
- conn.close();
- } catch (PropertyVetoException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Уведомление:
Соединение, полученное традиционным методом: com.mysql.cj.jdbc.ConnectionImpl@3c153a1
Соединение, полученное C3P0: com.mchange.v2.c3p0.impl.NewProxyConnection@6156496
так,Хотя все они вызывают метод close, классы реализации разные, поэтому и переписывание метода тоже разное. Это полиморфизм интерфейса.。
Метод close в C3P0 не уничтожает ресурс соединения напрямую, а возвращает соединение в пул соединений с базой данных.
Описанный выше способ настройки параметров пула подключений к базе данных написан непосредственно в Java-программе.
Это принятожесткий кодПуть,Каждый раз, когда вы меняете конфигурациюНужно перекомпилировать, генерировать новые файлы классов, эффективность слишком низкая。
В реальной разработке информация о конфигурации C3P0 определяется в XML-файле, и Java-программе достаточно загрузить файл конфигурации, чтобы завершить операцию инициализации пула соединений с базой данных.
В дальнейшем вам нужно будет только изменить конфигурацию и изменить конфигурацию в xml без перекомпиляции.
Шаги по использованию:
① В каталоге ресурсов создайте новый файл с именем c3p0-config.xml.
② Заполните информацию о конфигурации в c3p0-config.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <c3p0-config>
- <!--配置连接池mysql-->
- <named-config name="C3P0Test">
- <!-- 指定连接数据源的基本属性 -->
- <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
- <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8</property>
- <property name="user">root</property>
- <property name="password">123456</property>
-
- <!-- 设置初始化连接个数 -->
- <property name="initialPoolSize">5</property>
- <!-- 设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限) -->
- <property name="maxPoolSize">20</property>
- <!-- 当连接对象不够时,再次申请的连接对象个数 -->
- <property name="acquireIncrement">5</property>
- <!-- 设置最小连接数(当连接池中剩余2个连接对象时,就去申请 -> 提前做准备) -->
- <property name="minPoolSize">2</property>
- </named-config>
- </c3p0-config>
③Написание Java-программы.
- public class DataSourceTest {
- public static void main(String[] args) {
- try {
- //创建C3P0数据库连接池
- ComboPooledDataSource dataSource=new ComboPooledDataSource("C3P0Test");
- Connection conn=dataSource.getConnection();
- System.out.println(conn);
- //将连接还回到数据库连接池中
- conn.close();
- }catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Уведомление:
① Параметр в методе построения ComboPooledDataSource — это значение атрибута name тега именованной конфигурации, настроенного в c3p0-config.xml.
② В настоящее время класс инструмента JDBC можно изменить следующим образом:
- public class JdbcUtil {
- private static DataSource dataSource;
-
- static {
- dataSource = new ComboPooledDataSource("C3P0Test");
- }
-
- // 获取数据库连接对象
- public static Connection getConnection() throws SQLException {
- Connection conn = null;
- try {
- conn = dataSource.getConnection();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return conn;
- }
-
- // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
- public static void release(Connection conn, Statement st, ResultSet rs) {
- try {
- if (rs != null) {
- rs.close();
- }
- if (st != null) {
- st.close();
- }
- if (conn != null) {
- conn.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- public static Student findById(Integer idx) {
- Connection conn = null;
- PreparedStatement st = null;
- ResultSet rs = null;
- Student stu = null;
- try {
- conn = JdbcUtil.getConnection();
-
- String sql = "select * from student where id = ?";
- PreparedStatement ps = conn.prepareStatement(sql);
- //给占位符 ? 填充数据
- ps.setInt(1, idx);
- rs = ps.executeQuery();
- //取出结果集的数据
- while (rs.next()) {
- Integer id = rs.getInt(1);
- String name = rs.getString(2);
- Double score = rs.getDouble(3);
- Date birthday = rs.getDate(4);
- stu = new Student(id, name, score, birthday);
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //关闭链接,释放资源
- rs.close();
- st.close();
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return stu;
- }
В приведенном выше коде операции заполнения заполнителей данными и извлечения данных из набора результатов слишком громоздки.
Если в таблице Student 100 атрибутов, то нам придется записать 100 строк в цикле while для получения данных, а также может потребоваться много строк для заполнения заполнителей.
Решение:DBUtils может помочь разработчикам завершить инкапсуляцию данных (сопоставление наборов результатов с объектами Java).
Шаги по использованию:
① Импортировать зависимости в pom.xml.
- <dependency>
- <groupId>commons-dbutils</groupId>
- <artifactId>commons-dbutils</artifactId>
- <version>1.6</version>
- </dependency>
② Напишите код
- public static Student findById(Integer idx) {
- Connection conn = null;
- Student stu = null;
- try {
- conn = JdbcUtil.getConnection();
-
- String sql = "select * from student where id = ?";
- //使用DBUtils
- QueryRunner qr = new QueryRunner();
- stu = qr.query(conn, sql, new BeanHandler<>(Student.class), idx);
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //关闭链接,释放资源
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return stu;
- }
На этом этапе заполнение заполнителей и извлечение набора результатов можно выполнить с помощью двух строк кода.
деталь:
① Метод запроса должен передать 4 параметра:
Объект подключения
SQL-оператор
Объект класса реализации интерфейса ResultSetHandler (тип преобразованного объекта должен быть Student.class).
Параметры для заполнения заполнителей
② Интерфейс ResultSetHandler используется для обработки наборов результатов. Он может преобразовывать запрошенные наборы результатов в объекты Java. Предоставляются следующие четыре класса реализации.
BeanHandler | Сопоставьте набор результатов с объектом Java (например, объектом Student). |
BeanListHandler | Сопоставьте набор результатов с коллекцией List (например: List<Student > ) |
MapHandler | Сопоставьте набор результатов с объектом коллекции Map. (т.е.: Карта<String,Object> ключ: имя атрибута; значение: значение атрибута) |
MapListHandler | Сопоставьте набор результатов с коллекцией MapList (т. е.: List <Map<<String,Object> >) |
③ Параметр для заполнения заполнителя является переменным параметром, поэтому можно передать любое количество параметров для удовлетворения различных потребностей пользователей.
④ Преобразованный класс объекта (класс Student) должен иметь конструктор без параметров, иначе программа сообщит об ошибке.
причина:Нижний уровень находит этот класс через Student.class, а затем черезмеханизм отраженияНайдите конструктор без параметров этого класса и создайте его объект.
⑤ Имя атрибута в классе должно совпадать с именем поля в таблице базы данных.
Потому что после создания объекта при присвоении значений свойствам объекта на основе набора результатов поиск и присвоение выполняются по имени.
Что такое МВК?
После того, как запрос поступает в приложение JavaWeb, контроллер получает запрос, выполняет обработку бизнес-логики и, наконец, возвращает результат пользователю (Представление + Модель).
В первые годы при работе с веб-приложениями пользователи напрямую обращались к уровню управления, а уровень управления мог напрямую управлять базой данных:
сервлет -- CRUD (добавление, удаление, изменение) --> база данных
В коде сервлета: обработка запросов, ответов, переходов между представлениями, обработка JDBC, обработка бизнес-кода и обработка логического кода.
Недостатки:Программа очень раздута и не удобна в обслуживании.
решение: Нет ничего, что нельзя было бы решить добавлением еще одного слоя, если есть, добавьте еще один слой!
Модель
вид
Контроллер (Сервлет)
В качестве примера возьмем вход пользователя и администратора:
Уровень контроллера:
- @WebServlet("/login")
- public class LoginServlet extends HttpServlet {
-
- private LoginService loginService = new LoginServiceImpl();
-
- /* 处理登录的业务逻辑*/
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String username = req.getParameter("username");
- String password = req.getParameter("password");
- String type = req.getParameter("type");
- Object object = loginService.login(username,password,type);
- if(object != null){
- HttpSession session = req.getSession();
- switch (type){
- case "reader":
- Reader reader = (Reader) object;
- session.setAttribute("reader",reader);
- //跳转到用户的首页
- resp.sendRedirect("/book?page=1");
- break;
- case "admin":
- Admin admin = (Admin) object;
- session.setAttribute("admin",admin);
- //跳转到管理员的首页
- resp.sendRedirect("/admin?method=findAllBorrow&page=1");
- break;
- }
- }else{
- resp.sendRedirect("login.jsp");
- }
- }
-
- }
Сервисный уровень:
- public interface LoginService {
- //利用多态,动态返回不同类型的对象
- public Object login(String username,String password,String type);
- }
- public class LoginServiceImpl implements LoginService {
-
- private ReaderRepository readerRepository = new ReaderRepositoryImpl();
- private AdminRepository adminRepository = new AdminRepositoryImpl();
-
- @Override
- public Object login(String username, String password,String type) {
- Object object = null;
- //业务逻辑处理:根据type的值,来选择调用不同的登录方法,去查找不同的表
- switch (type){
- case "reader":
- object = readerRepository.login(username,password);
- break;
- case "admin":
- object = adminRepository.login(username, password);
- break;
- }
- return object;
- }
- }
Уровень Дао/Репозиторий:
- public interface AdminRepository {
- public Admin login(String username,String password);
- }
- public interface ReaderRepository {
- public Reader login(String username,String password);
- }
- public class AdminRepositoryImpl implements AdminRepository {
- //管理员的登录方法(和数据库交互)
- @Override
- public Admin login(String username, String password) {
- Connection connection = JDBCTools.getConnection();
- String sql = "select * from bookadmin where username = ? and password = ?";
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- Admin admin = null;
- try {
- statement = connection.prepareStatement(sql);
- statement.setString(1,username);
- statement.setString(2,password);
- resultSet = statement.executeQuery();
- if(resultSet.next()){
- admin = new Admin(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3));
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JDBCTools.release(connection,statement,resultSet);
- }
- return admin;
- }
- }
- public class ReaderRepositoryImpl implements ReaderRepository {
- //用户的登录方法(和数据库交互)
- @Override
- public Reader login(String username, String password) {
- Connection connection = JDBCTools.getConnection();
- String sql = "select * from reader where username = ? and password = ?";
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- Reader reader = null;
- try {
- statement = connection.prepareStatement(sql);
- statement.setString(1,username);
- statement.setString(2,password);
- resultSet = statement.executeQuery();
- if(resultSet.next()){
- reader = new Reader(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3),resultSet.getString(4),resultSet.getString(5),resultSet.getString(6),resultSet.getString(7));
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JDBCTools.release(connection,statement,resultSet);
- }
- return reader;
- }
- }