JavaWeb学习笔记(上)
javaWeb項目結構
MySQL
注意sql sever和my sql的語法是不一樣的
數據庫的理解
結構化查詢語言
DDL 數據庫操作
SQL基本語法
在MySQL Command Line Client 或者navicat等工具中都可以編寫SQL指令
- SQL指令不區分大小寫
- 每條SQL表達式結束之后都以;結束
- SQL關鍵字之間以空格進行分隔
- SQL之間可以不限制換行(可以有空格的地方就可以有換行)
數據庫的查詢,創建,修改,刪除
查詢數據庫
## 顯示當前mysql中的數據庫列表 show databases;## 顯示指定名稱的數據的創建的SQL指令 show create database <dbName>;創建數據庫
## 創建數據庫 dbName表示創建的數據庫名稱,可以自定義 create database <dbName>;## 創建數據庫,當指定名稱的數據庫不存在時執行創建 create database if not exists <dbName>;## 在創建數據庫的同時指定數據庫的字符集(字符集:數據存儲在數據庫中采用的編碼格式 utf8 gbk) create database <dbName> character set utf8;修改數據庫
修改數據庫字符集
## 修改數據庫的字符集 alter database <dbName> character set utf8; # utf8 gbk刪除數據庫 刪除數據庫時會刪除當前數據庫中所有的數據表以及數據表中的數據
## 刪除數據庫 drop database <dbName>;## 如果數據庫存在則刪除數據庫 drop database is exists <dbName>;使用/切換數據庫
use <dbName>基本表的創建,修改,刪除
下面標注為黃色的為常用的,其他的不怎么使用
注意:
char與varchar的區別:char指的是長度不可變字符串,varchar指的是長度可變字符串
char后面的數字指的是最長的字符串長度,長度不夠的話系統會自動補空格
而且varchar后面的數字也是指的最大長度,不過會根據實際的長度來使用,長度為4就用4個空間
創建數據表
數據表實際就是一個二維的表格,一個表格是由多列組成,表格中的每一類稱之為表格的一個字段
create table students(stu_num char(8) not null unique,stu_name varchar(20) not null,stu_gender char(2) not null,stu_age int not null,stu_tel char(11) not null unique,stu_qq varchar(11) unique );查詢數據表
show tables;查詢表結構
desc <tableName>;刪除數據表
## 刪除數據表 drop table <tableName>;## 當數據表存在時刪除數據表 drop table if exists <tableName>;修改數據表
## 修改表名 alter table <tableName> rename to <newTableName>;## 數據表也是有字符集的,默認字符集和數據庫一致 alter table <tableName> character set utf8;## 添加列(字段) alter table <tableName> add <columnName> varchar(200);## 修改列(字段)的列表和類型 alter table <tableName> change <oldColumnName> <newCloumnName> <type>;## 只修改列(字段)類型 alter table <tableName> modify <columnName> <newType>;## 刪除列(字段) alter table stus drop <columnName>;刪除
主鍵約束
數據的查詢,插入,修改,刪除
查詢
聚合函數
日期函數
字符串函數
分組查詢
這里與sql server的區別就是分組后不聚合依舊會顯示第一條數據
分頁查詢
插入
注意插入數據時intto后面的列名可以不用按表中的順序出現,但是value的值一定要與into后面的列名相對應,但如果你省略了列名,這需要按表中的列名的順序一樣
修改
刪除
索引的建立和刪除
刪除
數據表的關聯關系
一對一關聯
一對多關聯
多對多關聯
外鍵約束
對上面添加外鍵約束的一些理解:首先constraint 是關鍵字,FK…是邏輯名稱方便后面進行刪除可以隨便起名
然后是創建表的順序首先是創建沒有外鍵約束的表可以插入數據,然后創建有約束的表并建立關聯,最后插入數據
級聯
上面是添加外鍵時不添加級聯的方法,很麻煩,一般不使用
連接查詢,內連接,左 右外連接
內連接(只獲取條件匹配成功的數據)
使用on后他不會直接生成笛卡爾積,他會判斷連接條件是否成立先,如果不使用on的話會直接先生成笛卡爾積
左右外連接
嵌套查詢, 子查詢
UNION可以將多個查詢語句的結果整合在一起
注意這里與上面的區別,因為上面的只返回了一個值(單列單行),所以可以使用=來進行判斷
存儲過程
sql指令的執行過程
存儲過程的執行過程
存儲過程的創建及調用,變量使用,參數,分支if
創建存儲過程
調用存儲過程
注意上面的dual時什么?dual其實是一張系統表,我們定義的變量都會保存到這個表中
存儲過程中變量的使用
局部變量
用戶變量
變量賦值
存儲過程的參數
存儲過程的流程控制
循環語句
存儲過程管理
因為我們使用了native圖形界面所以可以很簡單的管理我們的存儲過程,可如果只使用sql語句又該如何管理存儲過程?
查詢存儲過程
修改存儲過程
刪除存儲過程
使用存儲過程實現借書案例
數據準備
-- 創建數據庫 create database db_test3;-- 使用數據庫 use db_test3;-- 創建圖書信息表: create table books(book_id int primary key auto_increment,book_name varchar(50) not null,book_author varchar(20) not null,book_price decimal(10,2) not null,book_stock int not null,book_desc varchar(200) );-- 添加圖書信息 insert into books(book_name,book_author,book_price,book_stock,book_desc) values('Java程序設計','亮亮',38.80,12,'亮亮老師帶你學Java'); insert into books(book_name,book_author,book_price,book_stock,book_desc) values('Java王者之路','威哥',44.40,9,'千鋒威哥,Java王者領路人');-- 創建學生信息表 create table students(stu_num char(4) primary key,stu_name varchar(20) not null,stu_gender char(2) not null,stu_age int not null );-- 添加學生信息 insert into students(stu_num,stu_name,stu_gender,stu_age) values('1001','張三','男',20); insert into students(stu_num,stu_name,stu_gender,stu_age) values('1002','李四','女',20); insert into students(stu_num,stu_name,stu_gender,stu_age) values('1003','王五','男',20);業務分析
游標
事務
MySQL事務管理
自動提交與手動提交
如何保證一致性?因為sql在數據庫的默認形勢下,一旦sql執行成功就會自動將結果提交到數據庫,就例如上圖第一個語句執行成功后就會自動提交,但是語句卻有可能因為錯誤而導致語句執行失敗,假如這兩個語句時有聯系的操作,那么這種情況就破壞了事務的一致性
事務隔離級別
設置數據庫的隔離級別
隔離級別就是上面表格中的級別,系統默認為可重復讀
數據庫設計
數據庫設計的三范式
數據庫建模
PowerDesigner
PowerDesigner的作用當我們建完模生成物理模型后,能自動幫我們生成sql語句,但我們一般不使用,因為生成的代碼不夠符合規范,氣死
PDMan
JDBC
JDBC介紹
入門案例
JDBC實現增刪改查
insert操作
刪除操作
修改操作
查詢操作
JDBC核心類與接口
DriverManager類
Connection接口
Statement接口
ResultSet接口
解決sql注入問題
例子如下:
刪除操作
添加操作
修改操作
根據ID查詢圖書信息
工具類的封裝
接口類的封裝
package com.qfedu.jdbc.utils;import java.sql.*;public class DBHelper {/*將創建數據庫連接所需的字符串定義為常量,集中管理*/private static final String DRIVER = "com.mysql.cj.jdbc.Driver";private static final String URL = "jdbc:mysql://localhost:3306/db_test3?characterEncoding=utf8";private static final String USERNAME = "root";private static final String PASSWORD = "@QFedu123";/*** 注冊驅動只需執行一次,因此我們放在幫助類的靜態初始化塊中完成*/static{try {Class.forName(DRIVER);} catch (ClassNotFoundException e) {System.out.println("-----------注冊驅動失敗");}}/*** 創建數據庫連接對象*/public static Connection getConnection(){Connection connection = null;try {connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);} catch (SQLException e) {System.out.println("-----------創建連接失敗");}return connection;}/*** 關閉連接* 多態的應用:使用Statement接口做參數,既可以傳遞Statement接口對象,* 也可以傳遞PreparedStatement接口對象*/public static void close(Statement statement, Connection connection){close(null,statement,connection);}/*** 關閉連接*/public static void close(ResultSet resultSet,Statement statement, Connection connection){try {if(resultSet!=null && !resultSet.isClosed()){resultSet.close();}if(statement!=null && !statement.isClosed()){statement.close();}if(connection!=null && !connection.isClosed()){connection.close();}}catch (Exception e){System.out.println("~~~~~關閉數據庫連接失敗");}}}DAO與DTO的封裝
例子如下:
實體類DTO封裝
public class Book implements Serializable {private int bookId;private String bookName;private String bookAuthor;private double bookPrice;private int bookStock;private String bookDesc;@Overridepublic String toString() {return "Book{" +"bookId=" + bookId +", bookName='" + bookName + '\'' +", bookAuthor='" + bookAuthor + '\'' +", bookPrice=" + bookPrice +", bookStock=" + bookStock +", bookDesc='" + bookDesc + '\'' +'}';}public Book() {}public Book(int bookId, String bookName, String bookAuthor, double bookPrice, int bookStock, String bookDesc) {this.bookId = bookId;this.bookName = bookName;this.bookAuthor = bookAuthor;this.bookPrice = bookPrice;this.bookStock = bookStock;this.bookDesc = bookDesc;}//get和set方法 }使用實體類封裝查詢操作返回的結果:
/** * 根據圖書ID查詢一條圖書記錄 */ public Book queryBook(int bid) throws SQLException{Book book = null;Connection connection = DBHelper.getConnection();String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books where book_id=?";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,bid);//通過executeQuery方法執行查詢語句,并且將查詢的結果存放到一個ResultSet對象中(結果集)ResultSet rs = preparedStatement.executeQuery();//處理結果:從rs中獲取查詢結果if(rs.next()){int id = rs.getInt("book_id");String name = rs.getString("book_name");String author = rs.getString("book_author");double price = rs.getDouble("book_price");int stock = rs.getInt("book_stock");String desc = rs.getString("book_desc");//我們需要將查詢到的一條數據庫圖書記錄的6個值返回book = new Book(id,name,author,price,stock,desc);}//關閉連接 結果集也需要關閉DBHelper.close(rs,preparedStatement,connection);return book; }使用DTO封裝查詢結果
package com.qfedu.jdbc.les1;import com.qfedu.jdbc.dto.Book; import com.qfedu.jdbc.utils.DBHelper;import java.sql.*; import java.util.ArrayList; import java.util.List;/*** @Description* @Author Java濤哥 @ 千鋒教育* @千鋒Java微信公眾號 Java架構棧*/ public class TestSelectBooks {public static void main(String[] args) throws ClassNotFoundException, SQLException {List<Book> list = new TestSelectBooks().listBooks();for(Book b:list){System.out.println(b.getBookName()+"\t"+b.getBookAuthor());}}public List<Book> listBooks() throws SQLException{List<Book> bookList = new ArrayList<>();//查詢所有圖書信息Connection connection = DBHelper.getConnection();String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books";Statement statement = connection.createStatement();ResultSet rs = statement.executeQuery(sql);while(rs.next()){int bookId = rs.getInt("book_id");String bookName = rs.getString("book_name");String bookAuthor = rs.getString("book_author");double bookPrice = rs.getDouble("book_price");int bookStock = rs.getInt("book_stock");String bookDesc = rs.getString("book_desc");Book book = new Book(bookId, bookName, bookAuthor, bookPrice, bookStock, bookDesc);bookList.add(book);}DBHelper.close(rs,statement,connection);return bookList;}}實體類傳遞添加、修改操作參數
添加操作
public boolean insertBook(Book book) throws SQLException {boolean flag = false;//調用工具類,獲取數據庫連接對象Connection connection = DBHelper.getConnection();String sql = "insert into books(book_name,book_author,book_price,book_stock,book_desc) values(?,?,?,?,?)";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1,book.getBookName());preparedStatement.setString(2,book.getBookAuthor());preparedStatement.setDouble(3,book.getBookPrice());preparedStatement.setInt(4,book.getBookStock());preparedStatement.setString(5,book.getBookDesc());int i = preparedStatement.executeUpdate(); flag = i>0;//關閉連接DBHelper.close(preparedStatement,connection);return flag; }修改操作
public boolean updateBook(Book book) throws SQLException{boolean flag = false;Connection connection = DBHelper.getConnection();String sql = "update books set book_name=?,book_author=?,book_price=?,book_stock=?,book_desc=? where book_id=?";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1,book.getBookName());preparedStatement.setString(2,book.getBookAuthor());preparedStatement.setDouble(3,book.getBookPrice());preparedStatement.setInt(4,book.getBookStock());preparedStatement.setString(5,book.getBookDesc());preparedStatement.setInt(6,book.getBookId());int i = preparedStatement.executeUpdate();flag = i>0;DBHelper.close(preparedStatement,connection);return flag;}DAO的封裝
import java.util.ArrayList; import java.util.List;/*** @Descript DAO Data Access Object 數據訪問對象* @Author 千鋒濤哥* 公眾號: Java架構棧*/ public class BookDAO {public boolean deleteBook(int bid) throws SQLException {boolean flag = false;//使用JDBC,根據圖書編號刪除圖書信息//1.注冊驅動 創建連接Connection connection = DBHelper.getConnection();//3.編寫SQLString sql = "delete from books where book_id=?";//4.如果SQL指令有參數占位符?,則從Connection獲取PreparedStatement預編譯SQL指令// 預編譯:在SQL指令中的參數賦值之前對SQL執行的語法結構進行編譯PreparedStatement preparedStatement = connection.prepareStatement(sql);// SQL指令預編譯之后,給SQL中的?賦值preparedStatement.setInt(1,bid);//5.執行SQLint i = preparedStatement.executeUpdate();//6.處理結果flag = i>0;//7.關閉連接DBHelper.close(preparedStatement,connection);return true;}/*** 添加圖書* @return 如果添加成功返回true,如果添加失敗則返回false* @throws SQLException*/public boolean insertBook(Book book) throws SQLException {boolean flag = false;//調用工具類,獲取數據庫連接對象Connection connection = DBHelper.getConnection();String sql = "insert into books(book_name,book_author,book_price,book_stock,book_desc) values(?,?,?,?,?)";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1,book.getBookName());preparedStatement.setString(2,book.getBookAuthor());preparedStatement.setDouble(3,book.getBookPrice());preparedStatement.setInt(4,book.getBookStock());preparedStatement.setString(5,book.getBookDesc());int i = preparedStatement.executeUpdate(); // 如果i>0,表示DML操作是成功的;如果i=0表示DML操作對數據表中的數據沒有影響flag = i>0;//關閉連接DBHelper.close(preparedStatement,connection);return flag;}/*** 根據圖書ID查詢一條圖書記錄*/public Book queryBook(int bid) throws SQLException{Book book = null;Connection connection = DBHelper.getConnection();String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books where book_id=?";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,bid);//通過executeQuery方法執行查詢語句,并且將查詢的結果存放到一個ResultSet對象中(結果集)ResultSet rs = preparedStatement.executeQuery();//處理結果:從rs中獲取查詢結果if(rs.next()){int id = rs.getInt("book_id");String name = rs.getString("book_name");String author = rs.getString("book_author");double price = rs.getDouble("book_price");int stock = rs.getInt("book_stock");String desc = rs.getString("book_desc");//我們需要將查詢到的一條數據庫圖書記錄的6個值返回book = new Book(id,name,author,price,stock,desc);}//關閉連接 結果集也需要關閉DBHelper.close(rs,preparedStatement,connection);return book;}public List<Book> listBooks() throws SQLException{List<Book> bookList = new ArrayList<>();//查詢所有圖書信息Connection connection = DBHelper.getConnection();String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books";Statement statement = connection.createStatement();ResultSet rs = statement.executeQuery(sql);while(rs.next()){int bookId = rs.getInt("book_id");String bookName = rs.getString("book_name");String bookAuthor = rs.getString("book_author");double bookPrice = rs.getDouble("book_price");int bookStock = rs.getInt("book_stock");String bookDesc = rs.getString("book_desc");Book book = new Book(bookId, bookName, bookAuthor, bookPrice, bookStock, bookDesc);bookList.add(book);}DBHelper.close(rs,statement,connection);return bookList;}public boolean updateBook(Book book) throws SQLException{boolean flag = false;Connection connection = DBHelper.getConnection();String sql = "update books set book_name=?,book_author=?,book_price=?,book_stock=?,book_desc=? where book_id=?";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1,book.getBookName());preparedStatement.setString(2,book.getBookAuthor());preparedStatement.setDouble(3,book.getBookPrice());preparedStatement.setInt(4,book.getBookStock());preparedStatement.setString(5,book.getBookDesc());preparedStatement.setInt(6,book.getBookId());int i = preparedStatement.executeUpdate();flag = i>0;DBHelper.close(preparedStatement,connection);return flag;}}DAO類中代碼的優化
1.在應用程序開發中,如果方法中拋出異常且自己可以處理,則直接通過try/catch進行捕獲處理;
2.JDBC操作方法的連接需要放在finally中進行關閉;
3.將數據庫連接Connection、Statement、ResultSet等需要關閉的數據庫對象定義在try之前;
4.因為所有的JDBC操作都需要Conection、Statement對象,查詢方法都需要ResultSet對象,因此在DAO中可以將這些對象定義成類的成員變量
package com.qfedu.jdbc.dao;import com.qfedu.jdbc.dto.Book; import com.qfedu.jdbc.utils.DBHelper;import java.sql.*; import java.util.ArrayList; import java.util.List;/*** @Descript DAO Data Access Object 數據訪問對象* @Author 千鋒濤哥* 公眾號: Java架構棧*/ public class BookDAO {private Connection connection;private Statement statement;private PreparedStatement preparedStatement;private ResultSet rs;public boolean deleteBook(int bid) {boolean flag = false;try{connection = DBHelper.getConnection();String sql = "delete from books where book_id=?";preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,bid);int i = preparedStatement.executeUpdate();flag = i>0;}catch(SQLException e){e.printStackTrace();}finally {DBHelper.close(preparedStatement,connection);}return flag;}public boolean insertBook(Book book) {boolean flag = false;try{//調用工具類,獲取數據庫連接對象connection = DBHelper.getConnection();String sql = "insert into books(book_name,book_author,book_price,book_stock,book_desc) values(?,?,?,?,?)";preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1,book.getBookName());preparedStatement.setString(2,book.getBookAuthor());preparedStatement.setDouble(3,book.getBookPrice());preparedStatement.setInt(4,book.getBookStock());preparedStatement.setString(5,book.getBookDesc());int i = preparedStatement.executeUpdate(); // 如果i>0,表示DML操作是成功的;如果i=0表示DML操作對數據表中的數據沒有影響flag = i>0;}catch (SQLException e){e.printStackTrace();}finally {DBHelper.close(preparedStatement,connection);}return flag;}public Book queryBook(int bid) {Book book = null;try {connection = DBHelper.getConnection();String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books where book_id=?";preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1, bid);//通過executeQuery方法執行查詢語句,并且將查詢的結果存放到一個ResultSet對象中(結果集)rs = preparedStatement.executeQuery();//處理結果:從rs中獲取查詢結果if (rs.next()) {int id = rs.getInt("book_id");String name = rs.getString("book_name");String author = rs.getString("book_author");double price = rs.getDouble("book_price");int stock = rs.getInt("book_stock");String desc = rs.getString("book_desc");//我們需要將查詢到的一條數據庫圖書記錄的6個值返回book = new Book(id, name, author, price, stock, desc);}}catch (SQLException e){e.printStackTrace();} finally {DBHelper.close(rs, preparedStatement, connection);}return book;}public List<Book> listBooks(){List<Book> bookList = new ArrayList<>();try {connection = DBHelper.getConnection();String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books";statement = connection.createStatement();rs = statement.executeQuery(sql);while (rs.next()) {int bookId = rs.getInt("book_id");String bookName = rs.getString("book_name");String bookAuthor = rs.getString("book_author");double bookPrice = rs.getDouble("book_price");int bookStock = rs.getInt("book_stock");String bookDesc = rs.getString("book_desc");Book book = new Book(bookId, bookName, bookAuthor, bookPrice, bookStock, bookDesc);bookList.add(book);}}catch (SQLException e){e.printStackTrace();}finally {DBHelper.close(rs, statement, connection);}return bookList;}public boolean updateBook(Book book) {boolean flag = false;try {connection = DBHelper.getConnection();String sql = "update books set book_name=?,book_author=?,book_price=?,book_stock=?,book_desc=? where book_id=?";preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1, book.getBookName());preparedStatement.setString(2, book.getBookAuthor());preparedStatement.setDouble(3, book.getBookPrice());preparedStatement.setInt(4, book.getBookStock());preparedStatement.setString(5, book.getBookDesc());preparedStatement.setInt(6, book.getBookId());int i = preparedStatement.executeUpdate();flag = i > 0;}catch (SQLException e){e.printStackTrace();} finally {DBHelper.close(preparedStatement, connection);}return flag;}}JDBC綜合案例
測試DAO中的方法
junit的使用
package com.qfedu.jdbc.test;import com.qfedu.jdbc.dao.StudentDAO; import com.qfedu.jdbc.dto.Student; import org.junit.Test;import java.util.List;import static org.junit.Assert.*;/*** @Descript 此類是StudentDAO的單元測試類* @Author 千鋒濤哥* 公眾號: Java架構棧*/ public class StudentDAOTest {//1.在測試類中定義成員變量:創建被測試類的對象private StudentDAO studentDAO = new StudentDAO();//2創建測試方法 : 用來測試StudentDAO類中的insertStudent方法//a.測試方法名=test+被測試方法名//b.測試方法無參數無返回值@Testpublic void testInsertStudent(){//準備被測試方法所需的參數Student stu = new Student("1008","Tom","男",20);//調用被測試方法,獲取結果boolean b = studentDAO.insertStudent(stu);//斷言返回結果(成立 | 不成立)assertTrue(b);}@Testpublic void testQueryStudent(){String snum = "1008";Student student = studentDAO.queryStudent(snum);assertEquals("Tom2",student.getStuName());}@Testpublic void testListStudents(){List<Student> studentList = studentDAO.listStudents();assertEquals(8,studentList.size());} }JDBC事務管理
步驟如下
3. 完成所有的操作后提交事務
4. 在出現異常后能夠進行回滾,一般將回滾操作放到catch中
例子如下:
package com.qfedu.jdbc.dao;import com.qfedu.jdbc.utils.DBHelper;import java.sql.*;/*** @Descript* @Author 千鋒濤哥* 公眾號: Java架構棧*/ public class BookDAO {/*** 借書:* @param stuNum 借書的學生學號* @param bookId 借書的圖書編號* @param num 借書的數量* @return*/public boolean borrowBook(String stuNum,int bookId,int num){boolean flag = false;Connection connection = null;PreparedStatement preparedStatement1 = null;PreparedStatement preparedStatement2 = null;try {connection = DBHelper.getConnectin();//設置使用當前Connection連接操作數據庫自動提交關閉connection.setAutoCommit(false);//1.向`records`表添加借書記錄String sql1 = "insert into records(snum,bid,borrow_num,is_return,borrow_date) values(?,?,?,0,sysdate())";preparedStatement1 = connection.prepareStatement(sql1);preparedStatement1.setString(1,stuNum);preparedStatement1.setInt(2,bookId);preparedStatement1.setInt(3,num);int i = preparedStatement1.executeUpdate();int k = 10/0; //造異常:算術異常//2.修改`books`表中的庫存String sql2 = "update books set book_stock=book_stock-? where book_id=?";preparedStatement2 = connection.prepareStatement(sql2);preparedStatement2.setInt(1,num);preparedStatement2.setInt(2,bookId);int j = preparedStatement2.executeUpdate();// 提交事務connection.commit();flag = i>0 && j>0;}catch (Exception e){try {//一旦事務執行過程中出現異常,執行回滾connection.rollback();} catch (SQLException ex) {ex.printStackTrace();}}finally {DBHelper.close(preparedStatement1,null);DBHelper.close(preparedStatement2,connection);}return flag;}}service層的事務管理
service層介紹
問題就是在serveces層中如果想要實現事務管理就必須保證,它調用的dao操作中的連接時一致的,可是顯然在不同的dao中獲取到的連接時不同的怎么班?
方法1:直接先在serves中獲取連接,然后將該鏈接發送到相關的dao操作中去(這種方法用的相對較少)
為什么不常使用:
方法2:使用ThreadLocal容器,實現多個DML操作使用相同的連接
對DBHelper代碼的進一步改進
我們可以使用list集合來保存connection,通過list來確保他們獲取的是同一個連接
但有一點需要注意的是我們在關閉連接是我們必須要在整個事務都完成后再關閉連接,不能像之前那樣完成一個dao操作就關閉連接,因為后面的dao操作可能還需要使用該連接
使用ThreadLocal進一步改進DBHelper
但使用list作為容器在多線程并發執行的操作下,會報錯因為如果操作的是同一個的連接,當其中一個線程將連接關閉會,可能會使其他的線程報錯
ThreadLocal容器的作用是:對于一個線程會為其創建一個鍵值對,就類似于map,所以對于一個線程來說第一次就是創建連接,第二次就是獲取之前創建的連接,所以使用ThreadLocal就可以解決多線程并發帶來的問題
整個例子:
注意因為使用了ThreadLocal來保存連接,所以在關閉連接的時候也需要獲取到相應的連接然后再關閉,而且關閉后需要將其從容器中移除
數據庫連接池
什么是數據庫連接池
我們現在的DAO操作中每一個操作都會申請連接,以及完成操作會回家給連接進行銷毀,即使使用了ThreadLocal也會在不同的線程拆功能鍵不同的連接,所以就會產生資源的浪費,所以就有了數據庫連接池
常用的數據庫連接池有哪幾種
目前市面上使用最多的是druid
使用數據庫連接池
package com.qfedu.jdbc.utils;import com.alibaba.druid.pool.DruidDataSource;import com.alibaba.druid.pool.DruidDataSourceFactory;import java.io.IOException;import java.io.InputStream;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;/*** @Descript Druid數據庫連接池工具類* @Author 千鋒濤哥* 公眾號: Java架構棧*/public class DruidUtils {//1.定義DruidDataSource對象:表示Druid數據庫連接池(數據源)private static DruidDataSource druidDataSource;//2.靜態代碼塊初始化定義DruidDataSource對象static{try {//讀取druid.properties文件中配置的屬性InputStream is = DruidUtils.class.getResourceAsStream("druid.properties");Properties properties = new Properties();properties.load(is);//使用屬性文件初始化DruidDataSource對象druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}//3.創建靜態方法,從連接池對象中獲取連接public static Connection getConnection(){Connection connection = null;try {connection = druidDataSource.getConnection();} catch (SQLException e) {e.printStackTrace();}return connection;}}通用的JDBC操作封裝
DML的操作封裝
具體代碼如下:
增加,刪除,修改的sql語句都是通過excuteUpdate來執行的,所以可以封裝在一起
DML的操作封裝
因為在不同的數據庫中的數據類型可能不一樣,有可能是student類型,也可能是book類型,也就是說不同的查詢中的返回類型可能不同,所以需要早封裝CommonDAO的時候我們使用反省,這樣就能根據new時所使用的參數來決定使用什么類型的參數
基于通用查詢的基本案例
DAO中的操作都是調用CommonDAO實現的
package com.qfedu.jdbc.dao;import com.qfedu.jdbc.dto.Book; import com.qfedu.jdbc.utils.CommonDAO; import com.qfedu.jdbc.utils.RowMapper;import java.sql.ResultSet; import java.sql.SQLException; import java.util.List;/*** @Descript 對圖書信息表進行CRUD操作* @Author 千鋒濤哥* 公眾號: Java架構棧*/ public class BookDAO {private CommonDAO<Book> commonDAO = new CommonDAO<>();public boolean insertBook(Book book){String sql = "insert into books(book_name,book_author,book_price,book_stock,book_desc) values(?,?,?,?,?)";boolean b = commonDAO.update(sql, book.getBookName(), book.getBookAuthor(), book.getBookPrice(), book.getBookStock(), book.getBookDesc());return b;}public boolean deleteBook(int bookId){String sql = "delete from books where book_id=?";boolean b = commonDAO.update(sql, bookId);return b;}public boolean updateBook(Book book){String sql="update books set book_name=?,book_author=?,book_price=?,book_stock=?,book_desc=? where book_id=?";boolean b = commonDAO.update(sql, book.getBookName(), book.getBookAuthor(), book.getBookPrice(), book.getBookStock(), book.getBookDesc(), book.getBookId());return b;}public Book queryBook(int bookId){String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books where book_id=?";RowMapper<Book> bookRowMapper = new RowMapper<Book>(){public Book getRow(ResultSet resultSet) throws SQLException {int bid = resultSet.getInt("book_id");String bookName = resultSet.getString("book_name");String bookAuthor = resultSet.getString("book_author");double bookPrice = resultSet.getDouble("book_price");int bookStock = resultSet.getInt("book_stock");String bookDesc = resultSet.getString("book_desc");return new Book(bid,bookName,bookAuthor,bookPrice,bookStock,bookDesc);}};List<Book> list = commonDAO.select(sql, bookRowMapper, bookId);return list.size()>0?list.get(0):null;}public List<Book> listBooks(){String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books";List<Book> list = commonDAO.select(sql, resultSet -> {int bid = resultSet.getInt("book_id");String bookName = resultSet.getString("book_name");String bookAuthor = resultSet.getString("book_author");double bookPrice = resultSet.getDouble("book_price");int bookStock = resultSet.getInt("book_stock");String bookDesc = resultSet.getString("book_desc");return new Book(bid, bookName, bookAuthor, bookPrice, bookStock, bookDesc);});return list;}}APache DBUtils
上面的commanDAO是我們自己封裝的,但是其實市面上已經有了相應的封裝,就是APache DBUtils我們可以直接引用
DButil的使用準備
11.3.1 創建Java應用
- 創建Java工程
- 添加驅動jar文件
11.3.2 創建連接池屬性配置
-
在src中創建package:com.qfedu.jdbc.utils
-
在com.qfedu.jdbc.utils中創建druid.properties文件
-
配置druid連接池的實行
11.3.3 創建連接池工具類
-
下載并導入druid的jar文件druid-1.2.8.jar
-
在com.qfedu.jdbc.utils創建DruidUtils工具類(工具類與屬性文件druid.properties在同目錄下)
DButil的使用
完成圖書信息的數據庫操作
- 創建實體類
13.3.1 添加操作
public int insertBook(Book book){int i= 0;try {//1.編寫SQLString sql = "insert into books(book_name,book_author,book_price,book_stock,book_desc) values(?,?,?,?,?)";//2.準備參數Object[] params = {book.getBookName(),book.getBookAuthor(),book.getBookPrice(),book.getBookStock(),book.getBookDesc()};//3.調用commons-dbutils中的QueryRunner執行SQLQueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());i = queryRunner.update(sql, params);} catch (SQLException e) {e.printStackTrace();}return i; }13.3.2 刪除操作
public int deleteBook(int bookId){int i = 0;try {String sql = "delete from books where book_id=?";QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());i = queryRunner.update(sql,bookId);} catch (SQLException e) {e.printStackTrace();}return i; }13.3.3 修改操作
public int updateBook(Book book){int i=0;try {String sql = "update books set book_name=?,book_author=?,book_price=?,book_stock=?,book_desc=? where book_id=?";Object[] params = {book.getBookName(),book.getBookAuthor(),book.getBookPrice(),book.getBookStock(),book.getBookDesc(),book.getBookId()};QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());i = queryRunner.update(sql, params);} catch (SQLException e) {e.printStackTrace();}return i; }13.3.4 查詢操作
查詢一條記錄
public Book queryBook(int bookId){Book book = null;try {String sql = "select book_id bookId,book_name bookName,book_author bookAuthor,book_price bookPrice,book_stock bookStock,book_desc bookDesc from books where book_id=?";QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());//1.對于查詢操作,我們需要通過QueryRunner對象調用query方法來執行//2.所有的query方法都需要一個ResultSetHandler的參數,通過此參數指定query方法的返回類型// 如果SQL指令執行之后返回的是一行記錄,我們通過BeanHandler指定查詢結果封裝的實體類類型// 要求:查詢結果集的字段名必須與指定的實體類的屬性名匹配// 方案1:創建實體類的時候,實體類中屬性的名字與數據表中的列名相同// 方案2:查詢語句字段取別名,讓字段別名與實體類屬性名一致book = queryRunner.query(sql, new BeanHandler<Book>(Book.class), bookId);} catch (SQLException e) {e.printStackTrace();}return book; }自定義結果集處理 自定義ResultSetHandler
public Book queryBook2(int bookId){Book book = null;try {String sql = "select book_id,book_name,book_author,book_price,book_stock,book_desc from books where book_id=?";QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());//1.對于查詢操作,我們需要通過QueryRunner對象調用query方法來執行//2.所有的query方法都需要一個ResultSetHandler的參數,通過此參數指定query方法的返回類型// 如果SQL指令執行之后返回的是一行記錄,我們通過BeanHandler指定查詢結果封裝的實體類類型// 要求:查詢結果集的字段名必須與指定的實體類的屬性名匹配// 方案3:自定義ResultSetHandler結果處理ResultSetHandler<Book> resultSetHandler = new ResultSetHandler<Book>() {@Overridepublic Book handle(ResultSet resultSet) throws SQLException {Book book = null;if(resultSet.next()) {int id = resultSet.getInt("book_id");String bookName = resultSet.getString("book_name");String bookAuthor = resultSet.getString("book_author");double bookPrice = resultSet.getDouble("book_price");int bookStock = resultSet.getInt("book_stock");String bookDesc = resultSet.getString("book_desc");book = new Book(id,bookName,bookAuthor,bookPrice,bookStock,bookDesc);}return book;}};book = queryRunner.query(sql, resultSetHandler, bookId);} catch (SQLException e) {e.printStackTrace();}return book; }查詢多條記錄
public List<Book> listBooks(){List<Book> bookList = null;try {String sql = "select book_id bookId,book_name bookName,book_author bookAuthor,book_price bookPrice,book_stock bookStock,book_desc bookDesc from books";QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());//如果SQL指令執行之后返回的是多行記錄,我們通過BeanListHandler指定查詢結果封裝的實體類的集合類型bookList = queryRunner.query(sql, new BeanListHandler<Book>(Book.class));} catch (SQLException e) {e.printStackTrace();}return bookList; }查詢一個值
例如在做分頁的時候,我們需要查詢數據的總記錄數
public long getCount(){long count = 0;String sql = "select count(1) from books";QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());// 如果SQL指令執行之后返回的是一個值時,我們通過ScalarHandler指定返回類型// QueryRunner在處理統計操作時,是以long類型進行操作的,因此不能直接轉成Integer// 如果我們確定這個值在int范圍內,我們可以在得到long類型之后進行強轉,建議使用long處理ScalarHandler<Long> scalarHandler = new ScalarHandler<Long>();try {count = queryRunner.query(sql, scalarHandler);} catch (SQLException e) {e.printStackTrace();}return count; }總結
以上是生活随笔為你收集整理的JavaWeb学习笔记(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统实验 连续内存分配 首次适应(F
- 下一篇: Java 构造函数的详解