MySql & JDBC

一、什麼是數據庫?
     數據庫就是存儲數據的倉庫,其本質是一個文件系統,數據按照特定的格式將數據存儲起來,用戶能夠經過SQL對數據庫中的數據進行增長、修改、刪除、及查詢操做。
數據庫系統類型(歷史發展):
網狀型數據庫
層次型數據庫
關係數據庫 ---理論最成熟、應用最普遍
面向對象數據庫
常見的數據庫(軟件):
MYSQL
Oracle
DB2
SQLServer
SyBase
SQLite
Java相關: MYSQL  Oracle
二、數據庫和表
數據表示存儲數據的邏輯單元,能夠把數據表想象成有行和列組成的表格,其中每一行也被稱爲一條記錄,每一列也被稱爲一個字段。(建表時:須要指定該表包含多少列,每列的數據的類型信息,無須指定包含多少行,數據庫的行是動態改變的。特殊列被稱爲主鍵列。)
三、SQL語句
什麼是SQL語句?
    Structured Query Language  結構化查詢語言。關係數據庫語言的國際標準。
SQL分類?
DDL:Data Definition Language 數控定義語言; 操做數據庫對象的語句,包括建立create、刪除drop、修改alter等(結構)
DML:Data Manipulation Language 數據操做語言,用來對數據庫表的記錄進行更新,包括插入insert 、 刪除 delete 、 更新 update等 (數據)
DQL: Data Query Language  數據查詢語言,用來查詢數據庫中表的記錄。關鍵字:select,from where等
DCL:Data Control Language 數據控制語言;用來定義數據庫的訪問權限和安全級別,及建立用戶:關鍵字 grant等
 
show databases;           查看當前實例下包含多少個數據庫
create     database  if not exists  數據庫名;    建立新的數據庫
create database  數據庫名 character set 字符集;
例子:create database web2 character set gbk;
查看某個數據庫的定義的信息:show create  database  數據庫名;
 
drop  database 數據庫名;         刪除指定數據庫
 
use  數據庫名;   切換數據庫、
查看正在使用的數據庫: select database();
 
show   tables;                查詢數據庫下包含多少數據表
desc  表名;            查看該表有多少列,每列的數據類型信息
 
DDL語句:
建立表:
create table 表名
     定義多個列定義;
);
修改表結構:
添加列:
alter table 表名
add (   能夠有多個列定義; 字段名  類型  [約束] , );
 
約束:
NOT NULL : 非空
UNIQUE:惟一約束 
PRIMARY KEY : 主鍵   
(test_id  int  auto_increment  primary key); 自增加特性,不能指定該列值
FOREIGN KEY: 外鍵
CHECK:檢查
 
修改列的類型、長度、約束:
alter table 表名   modify   要修改的字段名   類型(長度) 約束;
 
修改列的列名:
alter  table 表名
change  舊列名   新列名 類型(長度)  [約束];
 
刪除表的列:
alter table 表名 drop 表列名;
 
修改表名:
atler table 表名
rename   to  新表名;
 
修改表字符集:
alter table 表名  
character  set  編碼;
 
刪除表:
drop  table 表名;
 
DML語法:
插入新數據       insert into
修改已有數據    update 
刪除不須要的數據  deleter from 
 
insert:
語法:
insert into  表名  (列名1,列名2.....)values (值1,值2,....)......向表中插入某些列
insert into 表  values (值1,值2, 值3 ....)......向表中插入全部列
注意:
1.列名數與values後面的值得個數相等
2.列的順序與插入的值得順序一致
3.列名的類型與插入的值要一致
4.插入值得時候不能超過最大長度
5.值若是是字符串或者日期須要加引號‘’(通常都是單引號)
 
插入數據中文亂碼問題解決辦法:
方式一:[不建議]
直接修改數據庫安裝目錄裏面的 my.ini  文件的
第57行
default-character-set = utf8
 
方式二:
set  names  gbk;
 
update:
 
不帶條件的:
update  表名  set  字段值= 值
它會將該列的全部記錄都更改。
 
帶條件的:
update  表名  set  字段值 = 值  where  條件
 
delete:
 
帶條件的:
delete  from  表名  where   條件;
 
不帶條件:
delete  from  表名;  //記錄所有刪除
 
面試題:
說說delete 與truncate的區別?
Delete刪除的時候是一條一條的刪除記錄,它配合事務,能夠將刪除的數據找回。
Truncate刪除,它是將整個表摧毀,而後再建立一張如出一轍的表。它刪除的數據沒法找回。
truncate  table  表名;
 
 
start transaction;  開啓事務
delete from 表名;
select * from  表名;   //無數據
rollback;    //回滾下
select * from 表名;   //數據返回了
 
 
start  transaction;   開啓事務
truncate  table  表名; 
select * from  表名;  //無數據
rollback;   //回滾下
select * from 表名  ;  仍是無數據
insert  into  表名  values (值1,值2,....)
注:transaction再添加數據uid重置,從1開始,而delete刪除uid不會重置。(udi自增加的主鍵id,即定義以下:id int auto_increment primay key)。
 
四、DQL   SQL查詢   注:最最重要,用到最多
語法:
select  列名,列名   from   數據源   where   條件;
 
 
#建立商品表
create table product(
pid int primary key auto_increment,
pname varchar(20),
price double,
pdate timestamp
)
#自動增加列:auto_increment,要求:1,必須整型(int) 2.必須是主鍵
insert into product values (null,'譚妮平',0.01,null);
insert into product values (null,'李士雪',38,null);
insert into product values (null,'左慈',-998,null);
insert into product values (null,'黃迎',99999,null);
insert into product values (null,'南國強',99998,null);
insert into product values (null,'士兵',1,null);
insert into product values (null,'李士兵',698,null);
 
1.3.3 簡單查詢
1.查詢全部商品
select * from product;
2.查詢商品名和商品價格
select pname, price  from product;
3.查詢全部商品信息使用表別名
select * from product as p;
4.查詢商品名,使用列別名
select pname as  p  from product;
5.去掉重複值(按照價格,需有數據)
select  distinct(price) from product;
6.將全部的商品的價格+10進行顯示
select pname, price+10 from product;
 
1.3.4 條件查詢
比較運算符
> 、 <    =   >=   <=   <> (不等於)
between  ... .and  ...    顯示在某一區間的值(含頭含尾)
in ()   顯示在in列表中的值  
like  模糊查詢,like語句中,%表明0個或多個任意字符,_表明一個字符
轉義字符:MySQL使用反斜線(\)做爲轉義字符:
select * from student where sname like '\_%' (選出全部名字如下劃線開頭的學生)
is null   判斷是否爲空
邏輯運算符:
and  多個條件同時成立
or    多個條件任一成立
not  不成立 ,  例: where  not (salary > 100)
 
1.查詢商品名稱爲"左慈"的商品信息
select * from product where pname = '左慈'
2.查詢價格>60元的全部商品信息
select * from product where price > 60
3.查詢商品名稱含有"士"字的商品信息
select * from product where pname like '%士%'
4.查詢商品id在(3,6,9)範圍內的全部商品信息
select * from product where pid in (3,6,9);
 
1.3.5 排序(asc/desc)
1.查詢全部的商品,按價格進行排序(升序、降序)
select * from product order by price asc;   //升序
select * from product order by price desc; //降序
2.查詢名稱有"士"的商品信息而且按照價格降序排序
select * from product where  pname like '%士%'  order by price desc;
 
1.3.6 聚合
經常使用聚合函數: sum()求和,  avg()平均,  max()最大值,min()最小值,count()計數
注意:聚合函數不統計null值
1.得到全部商品的價格的總和
select sum(price) from product;
2.得到全部商品的平均價格
select avg(price) from product;
3.得到全部商品的個數
select count(*) from product;
select count(distinct pname) from product;
 
1.3.7 分組
1.添加分類id (alter table product add cid varchar(32);)
2.初始化數據
update product set cid='1';
update product set cid='2' where pid in (5,6,7);
查詢:
1.根據cid字段分組,分組後統計商品的個數。
select cid , count(*) from product group by cid;
2.根據cid分組,分組統計每組商品的平均價格,而且平均價格大於20000元。
select cid , avg(price)  from product group by cid having avg(price) >20000;
 
注意:若是須要對分組進行過濾,則應該使用having子句,having子句後面也是一個條件表達式,只有知足該條件表達式的分組纔會被選出來。
 
查詢總結:
select  *  |  字段 (通常放在"的"後面的內容都是要查詢的字段)
from    表
where  查詢條件
group by  分組字段
having     分組條件    分組後帶有條件只能使用having
order by    排序字段  asc 、desc  (必須放在最後)
 
五、回顧JDBC
設置工做空間的編碼:
windows->workspace->Text file encoding   -> other UTF-8。
建立JavaProject。
 
JDBC概述:
Java DataBase Connectivity: java 數據庫瞭解。
一、JDBC是一種用於執行SQL語句的Java API;
二、JDBC能夠爲多種關係數據庫提供統一訪問入口;
三、JDBC由一組Java工具類和接口組成。
 
應用程序  <----> JDBC  <---->  MySQL驅動  <-----> MySQL
a、手動添加jar包到工程中,Bulid Path---> Add  --->   出現小奶瓶就添加成功!
 
Junit測試:
package com.scalpel.test;
 
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
public class TestUnit {
public static void main(String[] args) {
System.out.println("aa");
}
 
@Test
public void testJunit()
{
System.out.println("hello junit!");
}
 
@Before
public void testBefore()
{
System.out.println("before!");
}
 
@After
public void testAfter()
{
System.out.println("after");
}
}
 
注:運行只能點擊testJunit() Run As   Junit Test.....
before!
hello junit!
after
 
JDBC開發步驟:
一、註冊驅動
Class.forName("com.mysql.jdbc.Driver");
二、得到鏈接
Connection   conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root","12345678");
DriverManager.getConnection(url, username, password):三個參數分別是url:jdbc的地址(位置,網址) ,  username 用戶名,  password  密碼。
三、得到語句執行者
經過Connection對象建立Statement對象。
Statement stmt = conn.createStatement();
四、執行sql語句
stmt.executeUpdate(String sql語句)   執行DML和DDL語句。 insert update   delete
(注:返回受影響的行數!!!)
stmt.executeQuery(String sql語句) 執行DQL 語句  select 語句 。
(注:返回表明查詢結果的ResultSet對象!!!)
ResultSet 實質是一個查詢結果集,記錄指針的初始位置是第一行以前。
(其餘方法:privious()/first()/last()/beforeFist()等等)
ResultSet  rs = stmt.executeQuery(sql語句)
五、處理結果
rs.next();
rs.getXxx();
 
六、釋放資源
棧(先進後出):
rs.close();
stmt.close();
con.close();
注:爲何要釋放資源?
 
JUnit Test:
 
package com.scalpel.test;
 
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
public class TestUnit {
public static void main(String[] args) {
System.out.println("aa");
}
 
@Test
public void testJunit()
{
System.out.println("hello junit!");
}
 
@Before
public void testBefore()
{
System.out.println("before!");
}
 
@After
public void testAfter()
{
System.out.println("after");
}
 
}
 
 
JDBC鏈接以及PreparedStatement執行SQL語句,防止SQL注入攻擊問題
 
package com.scalpel.test;
 
import java.sql.*;
 
import org.junit.Test;
 
 
 
public class TestLogin {
 
@Test
public void testLogin()
{
try {
login1("ct", "123");  //注:若是login (「‘or true or’」,"");也是登陸成功
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
 
public void login( String username, String password ) throws ClassNotFoundException, SQLException
{
/**
* 用戶登陸方法
* @author ctmc
*
*/
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲取鏈接
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
//3.建立執行sql語句的對象
Statement stmt = conn.createStatement();
//4.書寫一個sql語句
String sql = "select * from user where name = '" + username + "' and password = '" + password + "'" ;
//5.執行sql語句
ResultSet rs = stmt.executeQuery(sql);
//6.對結果集進行處理
if ( rs.next())
{
System.out.println("恭喜你,"+username+",登陸成功!");
System.out.println(sql);
}else
{
System.out.println("帳號或密碼錯誤");
}
//7.關閉資源
if(rs != null)
{
rs.close();
}
if( stmt != null )
{
stmt.close();
}
if(conn != null )
{
conn.close();
}
}
 
public void login1 ( String username, String password ) throws ClassNotFoundException, SQLException
{
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲取鏈接
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
//3.編寫sql語句
String sql = "select * from user where name = ? and password = ?";
//4.建立預處理對象
PreparedStatement pst = conn.prepareStatement(sql);
//5.設置參數(給佔位符)
pst.setString(1, username);
pst.setString(2, password);
//6.執行查詢操做
ResultSet rs = pst.executeQuery();
//7.對結果集進行處理
if ( rs.next())
{
System.out.println("恭喜你,"+username+",登陸成功!");
System.out.println(sql);
}else
{
System.out.println("帳號或密碼錯誤");
}
//8.關閉資源
if(rs != null)
{
rs.close();
}
if( pst != null )
{
pst.close();
}
if(conn != null )
{
conn.close();
}
}
}
 
注:使用PreparedStatement 防止SQL注入攻擊!!!?表明什麼
 
 
六、Limit關鍵字進行查詢操做(分頁查詢)
a、說出limit關鍵字兩個參數的含義
(limit 2, 2) : 第一個2起始位置, 第二個2每頁顯示的數目
每頁顯示3條件記錄,要查詢第3頁。
第一參數等於查詢的頁數減一乘以每頁顯示的數目,第二個參數是每頁顯示的數目
select * from product limit 6,3;
b、寫出limit關鍵字查詢數據SQL語句
 
總結:
一、說出JDBC的概念
二、說出JDBC的開發步驟
三、可以使用DriverManager類 (做用,加載驅動方法,獲取鏈接方法)
四、可以使用Connection接口 (做用,獲取接口的方法)
五、可以使用Statement接口
六、可以使用ResultSet接口
 
七、MySQL多表建立、查詢
外鍵:
從表外鍵的值是對主表主鍵的引用。
從表外鍵類型,必須與主表主鍵類型一致。
聲明外鍵約束:
alter table 從表 add [constraint] [外鍵名稱]  foreign key (從表外鍵字段名)  references 主表 (主表的主鍵);
用於刪除外鍵約束的,通常建議「_fk」結尾
alter  table 從表 drop  foreign key 外鍵名稱
使用外鍵的目的:
保證數據完整性。
注意事項:
從表不能添加一條主表中不存在的記錄。
主表不能刪除,從表中已經引用的記錄。
 
表與表之間的關係
a、一對多關係
一對多建表原則:在多的一方建立一個字段,字段做爲外鍵指向少的一方的主鍵。
alter table 從表(product) add  foreign key (外鍵cno) references 主表(category)主鍵(cid)
 
b、多對多關係
多對多關係建表原則:須要建立第三張表,中間表中至少兩個字段,這兩個字段分別做爲外鍵指向各自一方的主鍵。
alter table 從表(stu_course ) add foreign key(sno) references stu(sid);
alter table 從表(stu_course ) add foreign key(con) references course(cid);
 
c、一對一
兩種建表原則:
外鍵惟一:主表的主鍵和從表的外鍵惟一,造成主外鍵關係,外鍵惟一unique。
外鍵是主鍵:主表的主鍵和從表的主鍵,造成主外鍵關係。
 
多表查詢:
a、交叉鏈接查詢(基本不用)
     select * from A,B;
b、內鏈接查詢(使用關鍵字inner join   --inner能夠省略)
隱式內鏈接:select * from A,B where 條件
顯示內鏈接: select * from A  inner join B  on 條件 ;
c、外鏈接查詢(使用的關鍵字 outer join --outer 能夠省略)
左外鏈接:left outer join 
select * from A left outer join B on 條件;
右外鏈接:right outer join
select * from A right outer join B on 條件;
左外鏈接與右外鏈接的區別:
左外鏈接:左表所有及兩個表的交集
右外鏈接:查詢的是右邊表的所有及兩個表的交集。
內鏈接:查詢兩個表的交集。
全外鏈接:
d、子查詢
子查詢:一條select語句結果做爲另外一條select語法一部分(查詢條件,查詢結果,表等)
 
八、JDBC工具類抽取方式
使用JDBC發送select語句完成單表【查詢】操做。
//類:JDBCUtils_V1
 
package com.scalpel.jdbc;
/**
* 提供獲取鏈接和釋放資源的方法。
* @author ctmc
*
*/
import java.sql.*;
public class JDBCUtils_V1 {
    
    //鏈接Connection方法
    public static Connection getConnection()
    {
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }            
        return conn;        
    }
    
    //釋放全部資源方法
    public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
    {
        if( rs!= null )
        {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( psmt != null )
        {
            try {
                psmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( conn != null )
        {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
    }
}
 
//測試類TestUtils   
package com.scalpel.test;
import java.sql.*;
import org.junit.Test;
import com.scalpel.jdbc.JDBCUtils_V1;
 
/**
 * 測試工具類
 * @author ctmc
 *
 */
public class TestUtils {
       /**
        * 根據id查詢用戶信息.
        */       
       @Test
       public void testFindUserById()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             ResultSet rs = null;
             
             try {
             //1.獲取鏈接
             conn = JDBCUtils_V1.getConnection();
             String sql = "select * from user where id = ? ";
             //3.獲取執行SQL語句對象     
             pstmt =  conn.prepareStatement(sql);
             //4.設置參數
             pstmt.setInt(1, 2);
             //5.執行查詢操做
             rs = pstmt.executeQuery();
             //6.處理結果集
             while ( rs.next() )
             {
                    System.out.println(rs.getString("name")+"-----"+rs.getString("password"));
             }
             
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }finally {
                    //7.釋放資源
                    JDBCUtils_V1.release(conn, pstmt, rs);
             }
       }
}    
 
注意:一、PreparedStatement的用法。二、釋放資源爲何要放在finally中,能不能放在try中?    
 
PreparedStatement的用法:
數據庫的操做過程當中,PreparedStatement 對象是一個很不起眼可是記爲重要的接口對象,它繼承 於Statement,並與之在兩方面有所不一樣:
1)PreparedStatement 實例包含已編譯的 SQL 語句。這就是使語句「準備好」。包含於 PreparedStatement 對象中的 SQL 語句可具備一個或多個 IN 參數。IN參數的值在 SQL 語句建立時未被指定。相反的,該語句爲每一個 IN 參數保留一個問號(「?」)做爲佔位符。每一個問號的值必須在該語句執行以前,經過適當的setXXX 方法來提供。
2)因爲 PreparedStatement 對象已預編譯過,因此其執行速度要快於 Statement 對象。所以,屢次執行的 SQL 語句常常建立爲 PreparedStatement 對象,以提升效率。
例如:SQL語句爲:String sql = select * from  user  where  id = ?(整型)  and  name = ?(字符串);
在pstmt.setXXX設置是,第一個參數要整型,第二個參數爲字符串類型。
在ResultSet 得到結果。
rs.getString(1)  或者 rs.getString("name");獲得的結果同樣 (數據庫該表第一位爲name)!
 
九、使用properties配置文件
    開發中得到鏈接的4個參數(驅動、URL、用戶名、密碼)一般都保存在配置文件中,方便後期維護,程序若是須要更換數據庫,只須要修改配置文件便可。
    一般狀況下,咱們習慣使用properties文件,此文件咱們將作以下要求:
    a、文件位置:任意,建議放在src下(非web程序)
    b、文件名稱:任意,擴展名爲properties
    c、文件內容:一行一組數據,格式是:「key=value」(不要有空格)
     !key命名自定義,若是是多個單詞,習慣使用點分隔,例如:jdbc.driver
     @value值不支持中文,若是須要使用非英文字符,將進行unicode轉換
 
建立properties配置文件(注:不要有空格)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/web
username=root
password=12345678
加載配置文件----ResourceBundle對象
package com.scalpel.jdbc;
/**
* 提供獲取鏈接和釋放資源的方法。
* @author ctmc
*
*/
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCUtils_V2 {
    
     private static String  driver;
     private static String  url;
     private static String  username;
     private static String  password;
     /**
      * 靜態代碼塊加載配置文件信息。
      * */
    static
    {
        ResourceBundle rb = ResourceBundle.getBundle("db");
        driver = rb.getString("driver");
        url = rb.getString("url");
        username = rb.getString("username");
        password = rb.getString("password");
    }
    
    //鏈接Connection方法
    public static Connection getConnection()
    {
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url,username,password);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }            
        return conn;        
    }
    
    //釋放全部資源方法
    public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
    {
        if( rs!= null )
        {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( psmt != null )
        {
            try {
                psmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( conn != null )
        {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }       
    }      
}    
 
添加表信息:
       /**
        * 添加用戶信息方法
        */
       @Test
       public void testAdd()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             try {
                    //1.獲取鏈接
                    conn = JDBCUtils_V2.getConnection();
                    //2.編寫SQL語句
                    String sql = "insert into user values(?,?,null)";
                    //3.獲取執行sql語句對象
                    pstmt = conn.prepareStatement(sql);
                    //4.設置參數
                    pstmt.setString(1,"zll");
                    pstmt.setString(2,"zll");
                    //5.執行插入操做,返回一個值是否添加成功。
                    int row = pstmt.executeUpdate();
                    if ( row > 0 )
                    {
                           System.out.println("添加信息成功!");
                    }
                    else
                    {
                           System.out.println("添加失敗!");
                    }
                    
             } catch (Exception e) {
                    throw new RuntimeException(e);
             }finally {
                    //6.釋放資源
                    JDBCUtils_V2.release(conn, pstmt, null);
                    //注:無參數設置爲null
             }             
       }
 
根據ID刪除用戶信息:
配置文件加載方法改變:
package com.scalpel.jdbc;
/**
* 提供獲取鏈接和釋放資源的方法。
* @author ctmc
*
*/
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import java.util.ResourceBundle;
public class JDBCUtils_V3 {
    
     private static String  driver;
     private static String  url;
     private static String  username;
     private static String  password;
     /**
      * 靜態代碼塊加載配置文件信息。
      * */
    static
    {
        try {
            //1.經過當前類獲取類加載器
            ClassLoader cl = JDBCUtils_V3.class.getClassLoader();
            //2.經過類加載器的方法得到一個輸入流、
            InputStream is = cl.getResourceAsStream("db.properties");
            //3.建立一個properties對象
            Properties props = new Properties();
            //4.加載輸入流        
            props.load(is);
            //5.獲取相關參數的值
            driver = props.getProperty("driver");
            url = props.getProperty("url");
            username = props.getProperty("username");
            password = props.getProperty("password");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
         is.close();   
         }
    }
    
    //鏈接Connection方法
    public static Connection getConnection()
    {
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url,username,password);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }            
        return conn;        
    }
    
    //釋放全部資源方法
    public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
    {
        if( rs!= null )
        {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( psmt != null )
        {
            try {
                psmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( conn != null )
        {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }        
    }      
}    
 
注:實現全部資源釋放的方法,上例中使用多個try-catch塊,將資源釋放,容易理解。可是多個try-catch並列,catch塊中不能拋出異常,不然將阻止程序的繼續執行。
應該修改成:try-catch-finally嵌套,資源釋放時若是出錯,將通知調用者,還能夠繼續釋放其餘資源。
/**
        * 根據id刪除信息的方法
        */
       @Test
       public void testDleteById()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             try {
                    //1.獲取鏈接
                    conn = JDBCUtils_V3.getConnection();
                    //2.編寫SQL語句
                    String sql = "delete from user where id = ?";
                    //3.獲取執行sql語句對象
                    pstmt = conn.prepareStatement(sql);
                    //4.設置參數
                    pstmt.setInt(1,3);               
                    //5.執行插入操做
                    int row = pstmt.executeUpdate();
                    if ( row > 0 )
                    {
                           System.out.println("刪除信息成功!");
                    }
                    else
                    {
                           System.out.println("刪除失敗!");
                    }
                    
             } catch (Exception e) {
                    throw new RuntimeException(e);
             }finally {
                    //6.釋放資源
                    JDBCUtils_V2.release(conn, pstmt, null);
             }  
       }
 
十、Java項目讀取properties文件的幾種方法
1、項目中常常會須要讀取配置文件(properties文件),所以讀取方法總結以下: 
一、經過java.util.Properties讀取 
Java代碼 
  1. Properties p=new Properties();  
  2. //p須要InputStream對象進行讀取文件,而獲取InputStream有多種方法:  
  3. //一、經過絕對路徑:InputStream is=new FileInputStream(filePath);  
  4. //二、經過Class.getResourceAsStream(path);  
  5. //三、經過ClassLoader.getResourceAsStream(path);   經過本身的類加載最妥當!?why?
  6. p.load(InputStream is);  
  7. is.close();  
  8. p.getString(String(key))  
二、經過java.util.ResourceBundle讀取 
Java代碼  
  1. ResourceBundle rb=ResourceBundle.getBundle(packageName);  
  2. rb.getString(String key);  
 
十一、JDBC 鏈接池&DBUtils
鏈接池:解決資源浪費,提供代碼性能。
本小節目標:
使用DBCP,C3P0鏈接池完成基本數據庫的操做。
使用DBUtils完成CRUD的操做。
 
數據庫鏈接池的解決方案是:
當應用程序啓動時,系統主動創建足夠的數據庫鏈接,並將這些鏈接組成一個鏈接池。每次應用程序請求數據庫鏈接時,無須從新打開鏈接,而是從鏈接池中取出已有的鏈接使用,使用完後再也不關閉數據庫鏈接,而是直接將鏈接歸還給鏈接池。經過使用鏈接池,將大大提升程序的運行效率。
 
數據庫鏈接池是Connection 對象的工程。數據庫鏈接池的經常使用參數以下。
a、數據庫的初始鏈接數
b、鏈接池的最大鏈接數
c、鏈接池的最小鏈接數
d、鏈接池每次增長的容量
 
公共接口:javax.sql.DataSource。
常見的鏈接池:DBCP 、 C3P0 (主要)
 
1、自定義鏈接池
一、建立鏈接池實現(數據源),並實現接口javax.sql.DataSource。由於咱們只使用該接口中getConnection()方法。
二、提供一個集合,用於存放鏈接,由於移除、添加操做過多,因此選擇LinkedList
 
代碼例子:
提供獲取鏈接和釋放資源的方法仍是使用JDBCUtils_V3.java
package com.scalpel.DataSource;
 
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;
 
import javax.sql.DataSource;
import javax.sql.PooledConnection;
 
import com.scalpel.jdbc.JDBCUtils_V3;
 
public class MyDataSource implements DataSource {
       
       //1.建立一個容器,用於存儲Connection對象
       private static LinkedList<Connection> pool = new LinkedList<Connection>();
       
       //2.建立5個鏈接放到容器中去
       static
       {
             for (int i = 0; i < 5; i++)
             {
                    Connection conn = JDBCUtils_V3.getConnection();
                    pool.add(conn);                  
             }
       }
       /**
        * 重寫獲取一個鏈接的方法
        */
       @Override
       public Connection getConnection() throws SQLException {
             Connection conn = null;
             //3.使用前先判斷
             if( pool.size() == 0 )
             {
                    //4.池子裏面沒有,咱們在建立一些
                    for (int i = 0; i < 5; i++)
                    {
                           conn = JDBCUtils_V3.getConnection();
                           pool.add(conn);                  
                    }                   
             }
             //5.從池子裏面獲取一個鏈接對象Connection,list的remove()方法
             //刪除並返回index索引處的元素   
             conn  = pool.remove(0);          
             return conn;
       }
       
       /**
        * 歸還鏈接對象到鏈接池中去
        */
       public void backToPool ( Connection conn )
       {
             //鏈接用完後,再歸還到鏈接池中,直接插入到list集合中。
             pool.add(conn);            
       }
       
 
       @Override
       public PrintWriter getLogWriter() throws SQLException {
             // TODO Auto-generated method stub
             return null;
       }
 
       @Override
       public int getLoginTimeout() throws SQLException {
             // TODO Auto-generated method stub
             return 0;
       }
 
       @Override
       public Logger getParentLogger() throws SQLFeatureNotSupportedException {
             // TODO Auto-generated method stub
             return null;
       }
 
       @Override
       public void setLogWriter(PrintWriter out) throws SQLException {
             // TODO Auto-generated method stub
             
       }
 
       @Override
       public void setLoginTimeout(int seconds) throws SQLException {
             // TODO Auto-generated method stub
             
       }
 
       @Override
       public boolean isWrapperFor(Class<?> arg0) throws SQLException {
             // TODO Auto-generated method stub
             return false;
       }
 
       @Override
       public <T> T unwrap(Class<T> arg0) throws SQLException {
             // TODO Auto-generated method stub
             return null;
       }
 
       
 
       @Override
       public Connection getConnection(String username, String password) throws SQLException {
             // TODO Auto-generated method stub
             return null;
       } 
}
 
測試方法:
package com.scalpel.jdbc.test;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
 
import org.junit.Test;
 
import com.scalpel.DataSource.MyDataSource;
 
public class TestMyDataSource {
       
       @Test
       public void testAddUser()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             //建立自定義鏈接池對象
             MyDataSource dataSource = new MyDataSource();
             try
             {
                    //2.從池子中獲取鏈接
                    conn = dataSource.getConnection();
                    String sql = "insert into user values(?,?,null)";
                    pstmt = conn.prepareStatement(sql);
                    pstmt.setString(1, "xixi");
                    pstmt.setString(2, "456");
                    int rows = pstmt.executeUpdate();
                    if ( rows > 0 )
                    {
                           System.out.println("添加成功!");
                    }
                    else
                    {
                           System.out.println("添加失敗!");
                    }                   
             } catch (Exception e) {
                    throw new RuntimeException();
             }finally {
                    dataSource.backToPool(conn);
             }
       }
}
 
注:若是插入數據爲中文,會出現數據庫中亂碼顯示?
怎樣解決這個問題?
 
自定義鏈接池代碼實現改進(加強close方法):
    自定義鏈接池中存在的嚴重問題,用戶調用getConnection()得到鏈接後,必須使用release()方法進行鏈接的歸還,若是用戶調用conn.close()將鏈接真正的釋放,鏈接池中將出現無鏈接能夠。
 
方法加強的辦法:
a、繼承,子類繼承父類,將父類的方法進行復寫,從而進行加強。
    使用前提:必須有父類,且存在繼承關係。
b、裝飾者設計模式,此設計模式專門用於加強方法。
    使用前提:必須有接口
    缺點:須要將接口的全部方法都實現
c、動態代理:在運行時動態的建立代理類,完成加強操做。與裝飾者類似
    使用前提:必須有接口
    難點:須要反射技術
d、字節碼加強,運行時建立目標類子類,從而進行加強
    常見第三方框架:cglib 、javassist等。
 
C3P0鏈接池:
    C3P0開源免費的鏈接池!目前使用它的開源項目有:Spring 、 Hibernate等。使用第三方工具須要導入jar包,C3P0使用時還須要添加配置文件c3p0-config.xml(固定)
 
在增長、刪除、修改等操做中有不少相同的代碼,只有少部分的不一樣。對於那些不一樣的地方,咱們使用傳參的方法來解決!!!
    若是隻使用JDBC進行開發,咱們會發現冗餘代碼過多,爲了簡化JDBC開發,本案例咱們講採用apache commons組件一個成員:DBUtils。
    DBUtils就是JDBC的簡化開發工具包。須要使用技術:鏈接池(得到鏈接),SQL語句都沒有少。
 
JavaBean組件:
JavaBean就是一個類,在開發中經常使用語封裝數據。具備以下特性:
a、須要實現接口:java.io.Serializable  (一般省略)
b、提供私有字段:private 類型,字段名;
c、提供getter、setter方法;(空白處,source->setter  getter)
d、提供無參構造
 
放在com.scalpel.domain包中(構造方法)
package com.scalpel.domain;
 
public class User {
       private int id;
       private String password;
       private String name;
       
       
       public String getName() {
             return name;
       }
       public void setName(String name) {
             this.name = name;
       }
       public  User()
       {            
       }
       public int getId() {
             return id;
       }
       public void setId(int id) {
             this.id = id;
       }      
       
       public String getPassword() {
             return password;
       }
       public void setPassword(String password) {
             this.password = password;
       }      
}
 
注:JavaBean的私有字段名,必須與數據庫中的列名同樣!!!
不然查詢出來就是null。必須同樣。
 
DBUtils概述:
DBUtils是java編程中的數據庫操做實用工具,小巧簡單實用。
DBUtils封裝了對JDBC的操做,簡化了JDBC操做,能夠少些代碼。
DBUtils三個核心功能介紹:
a、QueryRunner中提供對sql語句操做的API
核心類:
QueryRunner( DataSource ds),鏈接池
update(String sql, Object ....params),執行更新數據
query(String sql, ResultSetHandler<t> rsh, Object ....params),執行查詢
b、ResultSetHandler接口,用於定義select操做後,怎樣封裝結果集
BeanHandler: 將結果集中第一條記錄封裝到一個指定的javaBean中。
BeanListHandler:將結果集中每一條記錄封裝到指定的javaBean中,將這些javaBean再封裝到集合中。
ScalarHandler
c、DbUtils類,它就是一個工具類,定義了關閉資源與事務處理的方法
 
c3p0-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
 
  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
       <property name="jdbcUrl">jdbc:mysql:///web</property>
       <property name="user">root</property>
       <property name="password">12345678</property>
       <property name="initialPoolSize">5</property>
       <property name="maxPoolSize">20</property>
  </default-config>
 
  <named-config name="scalpel">
    <property name="driverClass">com.mysql.jdbc.Driver</property>
       <property name="jdbcUrl">jdbc:mysql:///web</property>
       <property name="user">root</property>
       <property name="password">12345678</property>
  </named-config>
</c3p0-config>
 
C3P0Utils.java
package com.scalpel.jdbc.utils;
 
import java.sql.Connection;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
 
public class C3P0Utils {
       
       private static ComboPooledDataSource  dataSource =
                           new  ComboPooledDataSource("scalpel");  
       
       public static DataSource getDataSource()
       {
             return dataSource;         
       }
       
       public static Connection getConnection()
       {
             try {
                    return dataSource.getConnection();             
                    
             } catch (Exception e) {
                    throw new RuntimeException();
             }
       }      
 
}
 
TestDBUtils.java
package com.scalpel.jdbc.test;
 
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;
import com.scalpel.jdbc.utils.C3P0Utils;
 
/**
 * 測試DBUtils工具類
 * @author ctmc
 *
 */
public class TestDBUtils {
       
       @Test
       public   void testDeleteUserById()
       {
             try {
             //1.建立核心類QueryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.編寫sql語句
             String sql = "delete from user where id = ?";
             //3.爲佔位符設置值
             Object[] params = {7};
             //4.執行添加操做           
             int rows =  qr.update(sql,params);
             if ( rows > 0 )
             {
                    System.out.println("刪除成功");
             }
             else
             {
                    System.out.println("刪除失敗");
             }
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }      
       
       /**
        * 添加用戶
        */
       @Test
       public void testAddUser()
       {
             try {
             //1.建立核心類QueryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.編寫sql語句
             String sql = "insert into user values(?,?,null)";
             //3.爲佔位符設置值
             Object[] params = {"xizll","789"};
             //4.執行添加操做           
             int rows =  qr.update(sql,params);
             if ( rows > 0 )
             {
                    System.out.println("添加成功");
             }
             else
             {
                    System.out.println("添加失敗");
             }
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
 
}
 
查詢select代碼:
package com.scalpel.jdbc.test;
 
import java.sql.SQLException;
import java.util.List;
 
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;
 
import com.scalpel.domain.User;
import com.scalpel.jdbc.utils.C3P0Utils;
 
public class TestDBUtilsSelect {
       
       /*
        * 查詢全部用戶個數
        */
       @Test
       public void testUserNum()
       {
             try {
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             String sql = "select count(*) from user";                   
             long num =  (long) qr.query(sql, new ScalarHandler());
             System.out.println(num);
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }            
       }      
       
       /*
        * 根據id查詢用戶
        */
       @Test
       public void testQueryUserById()
       {
             try {
             //1.獲取核心類queryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.編寫sql語句
             String sql = "select * from user where id = ?";
             //3.爲佔位符設置值
             Object[] params = {9};
             //4.執行查詢操做     
             User user = qr.query(sql, new BeanHandler<User>(User.class), params);
             //5.對結果集單個進行輸出
             System.out.println(user.getName()+" : " + user.getPassword());                           
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
       
       /**
        * 查詢全部用戶
        * */
       @Test
       public void testQueryAll()
       {
             try {
             //1.獲取核心類queryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.編寫sql語句
             String sql = "select * from user";
             //3.執行查詢操做           
             List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));
             //4.對結果集集合進行遍歷
             for (User  user : users)
             {
                    System.out.println(user.getName()+" : " + user.getPassword());                    
             }            
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
 
}
相關文章
相關標籤/搜索