這一週我們學習了JDBC的各種功能,java實現了連接數據庫的接口,這樣操作起數據庫更加的方便了,我們還學了連接池,德魯伊等這是別人封裝好的jar包,這讓我們很多的使用起來非常的方便,最後我們進入了html學習,學習了簡單的html的標籤,表格,插入方式,最後還製作了一個比較好看的靜態網頁
下面是jdbc的筆記
JDBC
一、引言
1.1 如何操作數據
使用客戶端工具訪問數據庫,需要手工建立鏈接,輸入用戶名和密碼登錄,編寫SQL語句,點擊執行,查看操作結果(結果集或受影響行數)。
1.2 實際開發中,會採用客戶端操作數據庫嗎?
在實際開發過程中,當用戶的數據發生改變時,不可能通過客戶端操作執行SQL語句,因爲操作量過大!無法保證效率和正確性
二、JDBC(Java DataBase Connectivity)
2.1 什麼是JDBC?
JDBC(Java DataBase Connectivity) Java連接數據庫,可以使用Java語言連接數據庫完成CRUD操作
2.2 JDBC核心思想
Java中定義了訪問數據庫的接口,可以爲多種關係型數據庫提供統一的訪問方式。
由數據庫廠商提供驅動實現類(Driver數據庫驅動)
2.2.1 MySQL數據庫驅動
- mysql-connector-java-5.1.X 適用於5.X版本
- mysql-connector-java-8.0.X 適用於8.X版本
2.2.2 JDBC API
JDBC 是由多個接口和類進行功能實現
類型 全限定名 簡介
class java.sql.DriverManager 管理多個數據庫驅動類,提供了獲取數據庫連接的方法
interface java.sql.Connection 代表一個數據庫連接(當Connection不是NULL時,表示已連接一個數據庫)
interface java.sql.Statement 發送SQL語句到數據庫的工具
interface java.sql.ResultSet 保存SQL查詢語句的結果數據(結果集)
class java.sql.SQLException 處理數據庫應用程序時所發生的異常
2.3 環境搭建
- 在項目下新建 lib 文件夾,用於存放 jar 文件
- 將MySQL驅動文件mysql-connector-java-5.1.25-bin.jar 複製到項目的lib文件夾中
- 選中lib文件夾 右鍵選擇 add as library,點擊OK
三、JDBC開發步驟【重點】
3.1 註冊驅動
使用Class.forName(“com.mysql.jdbc.Driver”); 手動加載字節碼文件到JVM中
Class.forName("com.mysql.jdbc.Driver");
3.2 連接數據庫
-
通過DriverManager.getConnection(url,user,password);獲得數據庫連接對象
-
URL:jdbc:mysql://localhost:3306/database
-
user:root
-
password:1234
Connection connection = DriverManager.getConnection(“jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8”,“root”,“1234”);
-
-
URL(Uniform Resource Locator)統一資源定位符:由協議、IP、端口、SID(程序實例名稱)組成
3.3 獲取發送SQL的對象
通過Connection對象獲得Statement對象,用於對數據庫進行通用訪問的
Statement statement = connection.createStatement();
3.4 執行SQL語句
編寫SQL語句,並執行,接收執行後的結果
int result = statement.executeUpdate("update stu set student_name='高強',sex='女' where student_id = 'S1003'");
- 注意:在編寫DML語句時,一定要注意字符串參數的符號是單引號 ‘值’
- DML語句:增、刪、改時,執行的結果是受影響行數(int類型)。
- DQL語句:查詢時,返回的是數據結果集(ResultSet結果集)
3.5 處理結果
接收並處理操作結果
if(result > 0){
System.out.println("執行成功");
}
- 受影響行數:邏輯判斷,方法返回
- 查詢結果集:迭代、依次獲取
3.6 釋放資源
遵循的是先開後關的原則,釋放過程中用到的所有資源對象
statement.close();
connection.close();
3.7 綜合案例
綜合核心六步,實現增刪改
public static void main(String[] args)throws Exception {
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.連接數據庫
String url = "jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8";
String user = "root";
String password="1234";
Connection connection=DriverManager.getConnection(url,user,password);
//3.獲取發送SQL的對象
Statement statement = connection.createStatement();
//4.編寫SQL語句,執行SQL語句(返回受影響行數)
//新增
// String sql = "insert into stu(student_id,student_name,sex,birthday,phone,GradeId) values ('S1005','高強','女','1999-09-09','15612341234',3)";
// String sql = "delete from stu where student_id = 'S1005'";刪除
//修改
String sql = "update stu set student_name='高強',sex='女' where student_id = 'S1003'";
int result = statement.executeUpdate(sql);
//5.處理數據
if(result > 0){
System.out.println("執行成功!");
}
//6.釋放資源 先開後關
statement.close();
connection.close();
}
四、 ResultSet(結果集)
在執行查詢SQL後,存放查詢到的結果集數據
4.1 接收結果集
ResultSet rs = statement.executeQuery(sql)
ResultSet rs = statement.executeQuery("SELECT * FROM stu");
4.2 遍歷ResultSet中的數據
ResultSet以表(Table)結構進行臨時結果的存儲,需要通過JDBC API將其中的數據進行依次獲取
-
數據行指針:初始位置在第一行數據前,每調用一次boolean next()方法,ResultSet中指針向下移動一行,結果爲true,表示當前行有數據
-
rs.getXxx(“列名”); 根據列名獲得數據
-
rs.getXxx(整數下標); 代表根據列的編號順序獲得!從1開始
boolean next() throws SQLException;//判斷rs結果集中下一行是否有數據
4.2.1 遍歷方法
int getInt(int columnIndex) throws SQLException;//獲得當前行的第N列的int值
int getInt(String columnLabel) throws SQLException;//獲得當前行columnLabel列的int值
- 注意:列的編號從1開始
4.3 綜合案例
對stu表所有的數據進行遍歷
4.3.1 根據列的名稱獲取
package com.qf.day42.t2.basic;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestDql {
public static void main(String[] args) throws Exception{
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲得連接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8","root","1234");
//3.獲取執行SQL的對象
Statement statement = connection.createStatement();
//4.編寫SQL語句
String sql = "select student_id,student_name,sex,birthday,phone,GradeId from stu;";
ResultSet resultSet = statement.executeQuery(sql);
//5.處理結果 (結果集!)
while(resultSet.next()){//判斷結果集中是否有下一行!
//根據列名獲取當前行每一列的數據
String student_id = resultSet.getString("student_id");
String student_name = resultSet.getString("student_name");
String sex = resultSet.getString("sex");
String birthday = resultSet.getString("birthday");
String phone = resultSet.getString("phone");
int gradeId = resultSet.getInt("gradeId");
System.out.println(student_id+"\t"+student_name+"\t"+sex+"\t"+birthday+"\t"+phone+"\t"+gradeId);
}
//6.釋放資源
resultSet.close();
statement.close();
connection.close();
}
}
4.3.2 根據列的下標獲取
//5.處理結果 (結果集!)
while(resultSet.next()){//判斷結果集中是否有下一行!
//根據列的編號獲取當前行每一列的數據
String student_id = resultSet.getString(1);
String student_name = resultSet.getString(2);
String sex = resultSet.getString(3);
String birthday = resultSet.getString(4);
String phone= resultSet.getString(5);
int gradeId = resultSet.getInt(6);
System.out.println(student_id+"\t"+student_name+"\t"+sex+"\t"+birthday+"\t"+phone+"\t"+gradeId);
}
五、常見錯誤
- java.lang.ClassNotFoundException 找不到類(類名書寫錯誤、沒有導入jar包)
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException 與SQL語句相關的錯誤(表名列名書寫錯誤、約束錯誤、插入的值是String類型,但是沒有加單引號)建議:在客戶端工具中測試sql語句後,再粘貼到代碼中來
- com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘S1003’ for key ‘PRIMARY’ 原因:主鍵值已存在!更改要插入的主鍵值
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unknown column ‘password’ in
- 可能輸入的值的類型不對,確定插入元素時,對應的值的類型是否爭取
六、綜合案例【登錄】
6.1 創建表
- 創建一張用戶表 User
- id 主鍵、自動增長
- username 字符串類型 非空
- password 字符串類型 非空
- phone 字符串類型
- 插入2條測試語句
6.2 實現登錄
- 通過控制檯,用戶輸入用戶名和密碼
- 用戶輸入的用戶名和密碼作爲參數,編寫查詢SQL語句。
- 如果查詢到用戶,則用戶存在,提示登錄成功,反之,提示失敗!
七、SQL注入問題
7.1 什麼是SQL注入
當用戶輸入的數據中有SQL關鍵字或語法時,並且參與了SQL語句的編譯,導致SQL語句編譯後條件結果爲true,一直得到正確的結果。稱爲SQL注入
7.2如何避免SQL注入
由於編寫的SQL語句,是在用戶輸入數據後,整合後再編譯成SQL語句。所以爲了避免SQL注入的問題,使SQL語句在用戶輸入數據前,SQL語句已經完成編譯,成爲了完整的SQL語句,再進行填充數據
八、 PreparedStatement【重點】
PreparedStatement接口繼承了Statement接口。執行SQL語句的方法沒有區別!
8.1 PreparedStatement的應用
作用:1.預編譯SQL語句,效率高!
2.安全,避免SQL注入
3.可以動態的填充數據,執行多個同構的SQL語句
8.1.1 參數標記
//1.預編譯SQL語句
PreparedStatement pstmt = connection.prepareStatement(sql);
- 注意:PreparedStatement應用時,SQL字符串的參數都由?符號站位,被稱爲參數標記。在執行該SQL語句前,要爲每個?參數賦值
8.1.2 動態參數綁定
pstmt.setXxx(下標,值); 參數下標是從1開始,爲指定佔位符下標綁定值
//2.爲佔位符下標賦值
pstmt.setString(1,username);
pstmt.setString(2,password);
九、綜合練習
9.1創建數據庫、表
數據庫 Account
- 創建一張表 t_ccount。有以下列
- cardId:字符串,主鍵
- password:字符串,非空
- username:字符串,非空
- balance:小數,非空
- phone:字符串,非空
9.2 創建項目通過JDBC實現功能
創建AccountSystem類,完成下列功能
- 開戶:控制檯輸入所有的賬戶信息,使用PreparedStatement添加至t_account表
- 存款:控制檯輸入卡號、密碼、存儲金額進行修改
- 取款:輸入卡號、密碼、取款金額
- 轉賬:輸入卡號、密碼、對方卡號、轉賬金額進行修改
- 修改密碼:控制檯輸入卡號、密碼,再輸入新密碼進行修改
- 註銷:控制檯輸入卡號、密碼,刪除對應的賬戶信息
十、封裝工具類
10.1 重用性方案
- 封裝了獲取連接、釋放資源兩個方法
- 提供public static Connection getConnection()方法
- 提供public static void closeAll(Connection conn,Statement statement,ResultSet resultSet)
10.1.1 工具實現
package com.qf.day43.t1;
import sun.plugin2.gluegen.runtime.CPU;
import java.sql.*;
/**
* 數據庫工具類
* 1、提供連接 -->Connection
* 2、提供統一資源關閉
* 可重用性方案
*/
public class DBUtils {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//硬編碼
//獲得連接
public static Connection getConnection() {
Connection connection = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=UTF8", "root", "1234");
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
//釋放資源
public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
10.2 跨平臺方案
- 定義 private static final Properties properties = new Properties();//配置文件集合
- 定義static{
//首次使用工具類,觸發類加載
InputStream is = DBUtils.class.getResourceAsStream(“路徑”);//複用本類自帶流,讀取配置文件
properties.load(is);//將is流中的配置文件信息,加載到集合中
Class.forName(properties.getProperty(“driver”));
} - 在getConnection方法中。應用properties.getProperty(“url”);
10.2.1 實現
在src目錄下新建db.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8
username=root
password=123456
DBUtils代碼實現
package com.qf.day43.t2;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* 數據庫工具類
* 1、獲取連接 connection
* 2、釋放資源
* 可跨平臺方案
*/
public class DBUtils {
private static final Properties properties = new Properties();
static {
try {
//適用類自身自帶的流 路徑
InputStream is = DBUtils.class.getResourceAsStream("/db.properties");
properties.load(is);//通過流,將配置信息的內容分割成鍵值對
Class.forName(properties.getProperty("driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection connection = null;
try {
connection = DriverManager.getConnection(properties.getProperty("url"),properties.getProperty("username"),properties.getProperty("password"));
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//釋放資源
public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
十一、ORM
ORM(Object Relational Mapping)
從數據庫查詢到的結果集(ResultSet)在進行遍歷時,逐行遍歷,取出的都是零散的數據。在實際應用開發中,我們需要將零散的數據進行封裝整理
11.1 ORM 實體類(entity):零散數據的載體
- 一行數據中,多個零散的數據進行整理
- 通過entity的規則對錶中的數據進行對象的封裝
- 表名=類名;列名=屬性名;提供各個屬性的get、set方法
- 提供無參構造方法、(視情況添加有參構造)
11.1.1 ORM應用
package com.qf.day43.t2;
public class User {
private int id;
private String username;
private String password;
private String sex;
private String email;
private String address;
public User(){}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
", address='" + address + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public User(int id, String username, String password, String sex, String email, String address) {
this.id = id;
this.username = username;
this.password = password;
this.sex = sex;
this.email = email;
this.address = address;
}
}
package com.qf.day43.t2;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class OrmSelect {
public static void main(String[] args) {
Connection connection = DBUtils.getConnection();
String sql = "select id,username,PASSWORD,sex,email,address from `user`;";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
preparedStatement = connection.prepareStatement(sql);
System.out.println(preparedStatement);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {//拿到每一行數據、
//拿到每一列的數據
User user = new User();
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String password = resultSet.getString("password");
String sex = resultSet.getString("sex");
String email = resultSet.getString("email");
String address = resultSet.getString("address");
//將一行中零散的數據,封裝在一個User對象裏。
user.setId(id);
user.setUsername(username);
user.setPassword(password);
user.setSex(sex);
user.setEmail(email);
user.setAddress(address);
System.out.println(user);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(connection, preparedStatement, resultSet);
}
}
}
十二、DAO(Data Access Object)
數據訪問對象
- 將所有對同一張表的操作都封裝在一個XXXDaoImpl對象中。
- 根據增刪改查的不同功能,實現具體的方法(insert,update,delete,select,selectAll)
- 經驗:對於任何一張表中的數據進行操作時,無非就是增、刪、改、查。應將對於一張表的所有操作統一封裝在一個數據訪問對象中。重用
十三、日期類型
- java.util.Date
- Java語言常規應用層面的日期類型。可以通過字符串創建對應的時間對象
- 無法直接通過JDBC插入數據庫
- java.sql.Date
- 不可以通過字符串創建對應的時間對象。只能通過毫秒值創建對象(1970年1月1日至今的毫秒值)
- 可以直接通過JDBC插入數據庫
13.1 日期格式化工具
SimpleDateFormat 日期格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//按照指定格式轉換成util.Date類型
java.util.Date date = sdf.parse("2000-01-01");
13.2 日期工具類 DateUtil
package com.qf.day43.t4;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* 日期轉換
* 字符串轉UtilDate
* 字符串轉SqlDate
* utilDate轉成Sqldate
*/
public class DateUtils {
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//字符串轉Util
public static java.util.Date strToUtilDate(String str) {
try {
return simpleDateFormat.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
//字符串轉sql
// public static java.sql.Date strToSqlDate(String str){
// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
// try {
// java.util.Date date = simpleDateFormat.parse(str);
// return new java.sql.Date(date.getTime());
// } catch (ParseException e) {
// e.printStackTrace();
// }
// return null;
// }
//util轉sql
public static java.sql.Date utilToSql(java.util.Date date){
return new java.sql.Date(date.getTime());
}
}
13.2.1 測試
package com.qf.day43.t4;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDatetimes {
public static void main(String[] args) throws ParseException {
//1.java.util.Date 當前系統時間
// System.out.println(new java.util.Date());
//
// //自定義一個時間
// String str = "1999-09-09";
// //日期轉換 字符串轉爲 java.util.Date
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// //將日期字符串轉換成 util.Date類型
// java.util.Date utilDate = sdf.parse(str);
// System.out.println(utilDate);
//
// //sql.Date 需要毫秒值,來構建一個日期
// java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
// System.out.println(sqlDate);
//
//
// java.util.Date date = DateUtils.strToUtilDate("2002-3-18");
// System.out.println(date);
//
// java.sql.Date date2 = DateUtils.utilToSql(date);
// System.out.println(date2);
System.out.println(new java.util.Date());
System.out.println(new java.sql.Date(new java.util.Date().getTime()));
}
}
作業:user\userinfo
列名 類型 說明
user_id 整數、主鍵 用戶編號
user_name 字符串,唯一,非空 用戶名稱
user_pwd 字符串,非空 用戶密碼
user_borndate DATE 出生日期
user_email 字符串,非空 郵箱
user_address 字符串 地址
注意:採用DAO+Entity完成
com.qf.xxx.entity
User
com.qf.xxx.dao
UserDaoImpl
完成五個方法、增、刪、改、查、查所有
十四、連接池
JDBC每次連接數據庫,都要獲得一個連接對象。每次創建一個連接對象,都是一個較大的資源,如果在連接量較大的場景下,會極大的浪費資源。容易內存溢出。
14.1 自定義連接池
Java中提供了一個接口DataSource,通過實現該接口,可以創建連接池
14.2 Druid(德魯伊)
Druid 是目前比較流行高性能的,分佈式列存儲
一、亞秒級查詢
二、實時數據注入
三、可擴展的PB級存儲
四、多環境部署
五、豐富的社區
14.2.1 Druid配置
- 創建database.properties 配置文件
- 引入druid-1.1.5.jar
14.2.2 database.properties 文件配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/userinfo?useUnicode=true&characterEncoding=utf8
username=root
password=123456
#初始化連接
initialSize=10
#最大連接數量
maxActive=30
#最小空閒連接
minIdle=5
#超時等待時間以毫秒爲單位
maxWait=5000
14.2.3 連接池工具類
package com.qf.day44.t2;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.xml.transform.Result;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DBPoolUtils {
//連接池對象
private static DruidDataSource ds;
static {
Properties properties = new Properties();
InputStream is = DBPoolUtils.class.getResourceAsStream("/database.properties");
try {
properties.load(is);
//使用德魯伊工廠創建連接池
ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
//在連接池中獲得Connection
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 注意:連接池中獲得的Connection是DruidPooledConnection實現類,調用的close()方法不是關閉資源,而是將資源放回池中!
十五、Service(Biz/Business)
15.1 業務
概念:用戶要完成的一個業務功能,是由一個或多個的DAO調用組成。
軟件、程序提供的一個功能都叫業務
15.2 業務層的實現
package com.qf.day44.t3;
/**
* Userinfo的業務邏輯層對象
*/
public class UserinfoServiceImpl {
/**
* 用戶的註冊功能(業務)
*/
public String register(Userinfo userinfo){//1.接收參數
UserinfoDaoImpl userinfoDao = new UserinfoDaoImpl();
//2.調用數據訪問層對象的查詢方法!
Userinfo check = userinfoDao.select(userinfo.getUser_name());
if(check!=null){//用戶存在!~
return "用戶名已存在!";
}
//3.調用數據訪問層對象的新增方法
int result = userinfoDao.insert(userinfo);
//4.將操作結果返回給調用者
if(result >0 ){
return "註冊成功!";
}else{
return "註冊失敗!";
}
}
/**
* 登錄功能業務
*/
public Userinfo login(String user_name,String user_pwd){//收參
UserinfoDaoImpl userinfoDao = new UserinfoDaoImpl();
//2.調用數據訪問層對象的查詢方法
Userinfo userinfo = userinfoDao.select(user_name);
//3.接收結果,處理結果
if(userinfo!=null){//用戶存在!
//檢驗查詢到的用戶密碼和輸入的密碼是否一致!
if(userinfo.getUser_pwd().equals(user_pwd)){
return userinfo;
}
}
//4.響應給調用者結果
return null;
}
}
15.3 複用
- DAO數據訪問操作複用
- 業務功能的複用 //不同的終端訪問
15.4 轉賬案例
代碼參考Day44下的accounts項目
15.5 解決轉賬事務問題
1、傳遞Connection:如果將Service獲得的Connection對象,傳遞給DAO各個方法。可以。//BadSmell 臭味
定義接口是爲了更容易更換實現!而將Connection參數定義在接口方法中,就會污染當前接口,而無法複用。JDBC-Connection。MyBatis使用SqlSession
2、單例:當前項目只能有一個客戶端連接
十六、ThreadLocal
線程工具類:在整個線程中,一直到釋放資源,用的是同一個Connection連接對象。
16.1 ThreadLocal
1、在整個線程(單條執行路徑中)所持有的Map中,存儲一個鍵(threadlocal)值(connection)對
2、線程(Thread)對象中持有一個ThreadLocalMap類型的對象(ThreadthreadLocals),threadLocals中保存了以ThreadLocal對象爲Key,set進去的值爲Value
3、每個線程均可綁定多個ThreadLocal,一個線程中可存儲多個ThreadLocal
16.1.1 ThreadLocal代碼
//綁定到線程中! 綁定到當前線程中
ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();//0x112233
// Thread
//獲得當前線程對象-->t.threadLocals集合爲空-->create-->table[entry]-->key=0x112233 value=connection
threadLocal.set(null);
//獲得當前線程對象-->getMap--->t.threadLocals-->getEntry(0x112233)-->entry-->entry.value
Connection connection = threadLocal.get();
ThreadLocal<Integer> threadLocal1 = new ThreadLocal<Integer>();//0x2345
//每個線程可以綁定多個ThreadLocal,
threadLocal1.set(123);
Integer i = threadLocal1.get();
System.out.println(i);
16.2 ThreadLocal事務控制優化
將業務層的多步事務控制操作,封裝在DBUtils工具類裏。實現複用
16.2.1 DBUtils封裝事務控制
//開啓事務
public static void begin(){
Connection connection = getConnection();
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
//提交事務
public static void commit(){
Connection connection = getConnection();
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(connection,null,null);
}
}
//回滾事務
public static void rollback(){
Connection connection = getConnection();
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(connection,null,null);
}
}
十七、三層架構設計
- 表示層:
- 命名:xxxVIew
- 職責:收集用戶的數據和需求、展示數據
- 業務邏輯層
- 命名:XXXServiceImpl
- 職責:數據的加工處理、調用Dao組合完成業務實現、控制事務
- 數據訪問層
- 命名:xxxDaoImpl
- 職責:向業務層提供數據,將業務層加工處理後的數據同步到數據庫
十八、工具類型的封裝及普適性泛型工具
18.1 封裝DML方法
public int commonsUpdate(String sql, Object... args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = DBUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
return preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(null, preparedStatement, null);
}
return 0;
}
18.2 封裝DQL方法
/**
* 公共查詢方法 (可查詢單個對象,也可查詢多個對象,可以查任何一張表)
*
* @param sql
* @param args
* @return
*/
// select * from t_account
// select * from t_student
//工具不知道查的是什麼 調用者知道
//封裝對象、對象賦值 調用者清楚
public List<T> commonsSelect(String sql, RowMapper<T> rowMapper, Object... args) {
List<T> elements = new ArrayList<T>();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DBUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
if(args !=null){
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
}
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
//根據查詢到的結果完成ORM,如何進行對象的創建及賦值?
T t = rowMapper.getRow(resultSet);//回調---->調用者提供的一個封裝方法ORM
elements.add(t);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(null, preparedStatement, resultSet);
}
return elements;
}
十九、Apache的DbUtils使用
Commons DbUtils 是Apache組織提供的一個對JDBC進行簡單封裝的開源工具類庫,使用它能勾簡化JDBC應用程序的開發!同時,不會影響程序的性能
19.1 DbUtils簡介
- DbUtils是Java編程中數據庫操作實用小工具,小巧、簡單、實用
- 對於數據表的查詢操作,可以吧結果轉換爲List、Array、Set等集合。便於操作
- 對於數據表的DML操作,也變得很簡單(只需要寫SQL語句);
19.1.1 DbUtils主要包含
- ResultSetHandler接口:轉換類型接口
- BeanHandler類:實現類,把一條記錄轉換成對象
- BeanListHandler類:實現類,把多條記錄轉換成List集合。
- ScalarHandler類:實現類,適合獲取一行一列的數據。
- QueryRunner:執行sql語句的類
- 增、刪、改:update();
- 查詢:query();
19.2 DbUtils的使用步驟
- 導入jar包
- mysql連接驅動jar包
- druid-1.1.5.jar
- database.properties配置文件
- commons-dbutils-1.6.jar
19.2.1 代碼實現
DBUtils工具類
package com.project.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 連接池工具類
*/
public class DBUtils {
private static DruidDataSource dataSource;
static {
Properties properties = new Properties();
InputStream is = DBUtils.class.getResourceAsStream("/database.properties");
try {
properties.load(is);
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// 返回一個數據源
public static DataSource getDataSource(){
return dataSource;
}
}
UserDaoImpl 數據訪問對象
package com.project.dao.impl;
import com.project.dao.UserDao;
import com.project.entity.User;
import com.project.utils.DBUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.SQLException;
import java.util.List;
public class UserDaoImpl implements UserDao {
//1.創建QueryRunner對象,並傳遞一個數據源對象
private QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());
@Override
public int insert(User user) {
Object[] params={user.getId(),user.getUsername(),user.getPassword(),user.getSex(),user.getEmail(),user.getAddress()};
try {
return queryRunner.update("insert into user (id,username,password,sex,email,address) values(?,?,?,?,?,?)",params);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int update(User user) {
Object[] params={user.getUsername(),user.getPassword(),user.getSex(),user.getEmail(),user.getAddress(),user.getId()};
try {
return queryRunner.update("update user set username=?,password=?,sex=?,email=?,address=? where id = ?",params);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int delete(int id) {
try {
return queryRunner.update("delete from user where id = ?",id);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public User select(int id) {
try {
//把查詢到的記錄封裝成 指定對象
return queryRunner.query("select * from user where id = ?", new BeanHandler<User>(User.class), id);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 查詢所有
* @return
*/
@Override
public List<User> selectAll() {
try {
return queryRunner.query("select * from user;",new BeanListHandler<User>(User.class));
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}