一、什麼是數據庫?
數據庫就是存儲數據的倉庫,其本質是一個文件系統,數據按照特定的格式將數據存儲起來,用戶能夠經過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代碼
- Properties p=new Properties();
- //p須要InputStream對象進行讀取文件,而獲取InputStream有多種方法:
- //一、經過絕對路徑:InputStream is=new FileInputStream(filePath);
- //二、經過Class.getResourceAsStream(path);
- //三、經過ClassLoader.getResourceAsStream(path); 經過本身的類加載最妥當!?why?
- p.load(InputStream is);
- is.close();
- p.getString(String(key))
二、經過java.util.ResourceBundle讀取
Java代碼
- ResourceBundle rb=ResourceBundle.getBundle(packageName);
- 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();
}
}
}