在學(xué)習(xí)數(shù)據(jù)源連接池之前我們先來(lái)了解一個(gè)一種模式。
DAO模式:(使我們?cè)诰幊虝r(shí)經(jīng)常用到的一種編程模式)數(shù)據(jù)訪問(wèn)對(duì)象,它是標(biāo)準(zhǔn)的JavaEE設(shè)計(jì)模式的一種册养。
使用DAO模式可以把底層的數(shù)據(jù)訪問(wèn)操作和上層的業(yè)務(wù)邏輯分開(kāi)构拳。
一個(gè)DAO模式我們用三個(gè)組件來(lái)實(shí)現(xiàn):
1、DAO接口
2霞赫、DAO接口的具體實(shí)現(xiàn)類
3腮介、DAO工廠類
對(duì)于在JDBC的應(yīng)用中DAO接口主要是用于聲明我要實(shí)現(xiàn)的CURD操作:
我在這里做了一個(gè)Employee實(shí)例針對(duì)其進(jìn)行增刪查改,基于MySQL數(shù)據(jù)庫(kù)
1端衰、實(shí)現(xiàn)DAO接口叠洗,聲明我要實(shí)現(xiàn)的方法:
package dao;
import entity.Employee;
import entity.Page;
import java.util.List;
public interface EmpDao {
//插入
void save(Employee emp);
//修改
void update(Employee emp);
//刪除
void delete(int id);
//根據(jù)條件查詢某一條
Employee findone(int id);
//查詢所有記錄
List<Employee> findAll();
//模糊查詢
List<Employee> findByName(String name);
//統(tǒng)計(jì)總記錄數(shù)
long count();
//分頁(yè)查詢
Page<Employee> findAll(int number,int size);
}
有了接口我們接下來(lái)就需要DAO實(shí)現(xiàn)類來(lái)實(shí)現(xiàn)我們具體的操作:
public class EmpDaoMySQLImpl implements EmpDao {
//這里質(zhì)檢單羅列了增刪查改的功能
private static DataSource ds=DBUtils.getDateSource();
@Override
public void save(Employee emp) {
QueryRunner qr=new QueryRunner(ds);
String sql="INSERT INTO employee(name,joinTime,gender,job,salary) VALUES(?,?,?,?,?)";
try {
qr.update(sql,emp.getName(),emp.getJoinTime(),emp.getGender(),emp.getJob(),emp.getSalary());
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void update(Employee emp) {
Connection conn=null;
conn=DBUtils.getConnection();
QueryRunner qr=new QueryRunner();
String sql="UPDATE employee SET name=?,joinTime=?,gender=?,job=?,salary=? WHERE id=?";
try {
qr.update(conn,sql,emp.getName(),emp.getJoinTime(),emp.getGender(),emp.getJob(),emp.getSalary(), emp.getId());
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.close(conn);
}
}
@Override
public void delete(int id) {
Connection conn=null;
conn=DBUtils.getConnection();
QueryRunner qr=new QueryRunner();
String sql="DELETE FROM employee WHERE id=?";
try {
qr.update(conn,sql,id);
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.close(conn);
}
}
@Override
public Employee findone(int id) {
Connection conn=null;
Employee ee=null;
conn=DBUtils.getConnection();
QueryRunner qr=new QueryRunner();
String sql="SELECT id,name,joinTime,gender,job,salary From employee WHERE id="+id;
try {
//BeanHandler將結(jié)果集的第一行數(shù)據(jù),封裝成JavaBean對(duì)象
ee=qr.query(conn,sql,new BeanHandler<Employee>(Employee.class));
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.close(conn);
}
return ee;
}
}
最后一步就是通過(guò)DAO工廠類來(lái)產(chǎn)生具體的DAO實(shí)現(xiàn)類實(shí)例旅东,以為針對(duì)不同的數(shù)據(jù)庫(kù)我們可能會(huì)有不同的增刪查改及其他功能操作灭抑,為了后期的修改方便,我們把要實(shí)現(xiàn)的類放在一個(gè)properties文件里面抵代,通過(guò)Properties來(lái)加載具體的實(shí)現(xiàn)類即可腾节。
public class DaoFactory {
//dao工廠
private static Properties prop=new Properties();
static {
try {
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
//獲取實(shí)例
public static Object getInstance(String key){
String name=prop.getProperty(key);
Object obj=null;
try {
obj=Class.forName(name).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
就這樣我們的DAO模式就已經(jīng)實(shí)現(xiàn),這樣在我們執(zhí)行的時(shí)候
public class TestDruid {
public static void main(String[] args) {
//我們直接通過(guò)工廠類來(lái)來(lái)獲取具體實(shí)現(xiàn)類來(lái)執(zhí)行操作
EmpDao ed= (EmpDao) DaoFactory.getInstance("Empdao");
//新增數(shù)據(jù)
ed.save(new Employee(1,"嘿嘿",new Date(),"男","就是玩",2300));
}
那么接下來(lái)是要說(shuō)說(shuō)我們的數(shù)據(jù)源連接池的問(wèn)題了荤牍,這個(gè)問(wèn)題的緣由是由于當(dāng)我們的項(xiàng)目有很大的訪問(wèn)量是案腺,每個(gè)用戶的訪問(wèn)都需要新建連接進(jìn)行連接,我們的連接時(shí)間是最為耗時(shí)的康吵,為了防止同時(shí)多個(gè)客戶同時(shí)操作數(shù)據(jù)庫(kù)劈榨,我們就準(zhǔn)備了一個(gè)連接池,把我們的連接提前創(chuàng)建直接放在我們的池子里晦嵌,當(dāng)用的時(shí)候直接獲取使用就會(huì)大大提高我們的效率同辣。
數(shù)據(jù)源:數(shù)據(jù)源,作為DriverManager工具類的 替代項(xiàng)惭载,是用亍獲取數(shù)據(jù)庫(kù)連接的首選方式旱函。 其設(shè)置了我們確定數(shù)據(jù)的基本配置參數(shù)以及驅(qū)動(dòng)。
#mysql config
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mytest?serverTimezone=UTC
username=root
password=root
#druid配置初始化大小描滔、最小陡舅、最大
druid.initialSize=1
druid.minIdle=1
druid.maxActive=20
#配置獲取連接等待超時(shí)的時(shí)間
druid.maxWait=60000
#配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接伴挚,單位是毫秒
druid.timeBetweenEvictionRunsMillis=60000
# 配置一個(gè)連接在池中最小生存的時(shí)間靶衍,單位是毫秒
druid.minEvictableIdleTimeMillis=300000
druid.validationQuery=SELECT 'x’ druid.testWhileIdle=true
druid.testOnBorrow=false
druid.testOnReturn=false
#配置監(jiān)控統(tǒng)計(jì)攔截的filters
druid.filters=stat
maxOpenPreparedStatements=20
removeAbandoned=true
removeAbandonedTimeout=1800
logAbandoned=true
然后我們引用了Alibaba的druid.jar包灾炭,其效率是目前最快的。
public class DBUtils {
//通過(guò)druid數(shù)據(jù)庫(kù)連接池來(lái)獲取連接
private static Properties prop = new Properties();
private static DataSource ds = null;
static {
try {
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(prop);
} catch (IOException e) {
System.out.println("未找到配置文件");
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//需要從連接池獲取 通過(guò)DataSource
public static Connection getConnection(){
Connection conn=null;
try {
conn=ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static DataSource getDateSource(){
return ds;
}
}
這樣基本的原理及使用流程就實(shí)現(xiàn)了颅眶。