千鋒逆戰班,第九周總結

這一週我們學習了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 環境搭建

  1. 在項目下新建 lib 文件夾,用於存放 jar 文件
  2. 將MySQL驅動文件mysql-connector-java-5.1.25-bin.jar 複製到項目的lib文件夾中
  3. 選中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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章