前言
在講解Web開發模式的時候,曾經寫過XML版的使用者登陸註冊案例!現在在原有的專案上,使用資料庫版來完成使用者的登陸註冊!如果不瞭解的朋友,可以看看我Web開發模式的博文!
本來使用的是XML檔案作為小型資料庫,現在使用Mysql資料庫,程式碼究竟要改多少呢?我們拭目以待!
使用C3P0資料庫連線池
匯入C3P0的開發包和匯入配置檔案
開發包匯入的是這個:c3p0-0.9.2-pre1和mchange-commons-0.2.jar.
C3P0不僅效能好,而且配置檔案可以使用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://localhost:3306/zhongfucheng</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/zhongfucheng</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
<named-config name="oracle">
<property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
<property name="jdbcUrl">jdbc:oracle:thin:@//localhost:1521/事例名...</property>
<property name="user">使用者名稱</property>
<property name="password">密碼</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config>
複製程式碼
寫獲取連線的工具類
public class DBUtils {
private static ComboPooledDataSource comboPooledDataSource = null;
static {
//它會自動尋找配置檔案,節點為mysql的資料庫【如果沒有指定,就使用預設的!】
comboPooledDataSource = new ComboPooledDataSource("mysql");
}
public static DataSource getDataSource() {
return comboPooledDataSource ;
}
public static Connection getConnection() {
try {
return comboPooledDataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("資料庫初始化失敗了!");
}
}
}
複製程式碼
設計資料庫表
非常簡單,根據實體表來設計就好了!
CREATE TABLE user (
id VARCHAR(20) PRIMARY KEY,
username VARCHAR(20) UNIQUE NOT NULL,
password VARCHAR(20) NOT NULL,
email VARCHAR(20),
birthday DATE
);
複製程式碼
寫一個運算元據庫的Dao實現
public class UserImplDataBase implements UserDao {
@Override
public User find(String username, String password) {
return null;
}
@Override
public void register(User user) {
}
}
複製程式碼
下面我們就直接使用DBUtils框架了
- 匯入DBUtils的開發包
- 具體的程式碼如下
@Override
public User find(String username, String password) {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "SELECT * FROM user WHERE username=? AND password=?";
try {
User user = (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{username, password});
return user == null ? null : user;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("登陸失敗了!");
}
}
@Override
public void register(User user) {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "INSERT INTO user (id, username, password, email,birthday) VALUES (?,?,?,?,?);";
String id = user.getId();
String username = user.getUsername();
String password = user.getPassword();
String email = user.getEmail();
Date date = user.getBirthday();
try {
queryRunner.update(sql, new Object[]{id, username, password, email,date});
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("註冊失敗了");
}
}
}
複製程式碼
開發DaoFactory
我們的Dao實現已經有了XML版和JDBC版的,BusinessService呼叫Dao層方法的時候還是要new出具體的Dao實現,也就是以下的程式碼:
UserDao userDao = new UserImplXML();
//或者
UserDao userDao= new UserImplDataBase();
複製程式碼
這樣做有點不夠靈活,也就有點不夠專業!下面我們來說一下為什麼需要DaoFactory?
為什麼需要DaoFactory?
參考博文:blog.sina.com.cn/s/blog_4ca3…
摘抄重點:
優點:
- 透明化:商業物件可以在完全不知道資料來源如何具體實現的情況下來使用資料來源. 訪問資料來源是透明的,因為實現細節已經被隱藏進了DAO.
- 遷移簡單化:DAO 層的出現,使得應用程式向不同的資料庫實現進行遷移變的容易.商業物件可以對底層資料實現一無所知.這樣,遷移只涉及到了對DAO層的修改. 另外,如果使用工廠策略,則使為每一種底層資料實現提供一個具體的工廠實現成為可能.在這種情況下,遷移到一種不同的資料實現,其實就相當於為這個應用程式再提供一個新的工廠實現.
- 減少在商業物件中的程式設計難度:由於DAO管理著所有的資料訪問細節,因而大大簡化了在商業物件和其他使用DAO的資料客戶端裡的程式碼.所有的實現細節相關的程式碼比如(SQL 語句)都包含在DAO而不在商業物件中. 這樣使得程式碼變的更加健壯而且大大提高了開發效率.
- 將所有的資料訪問都單獨集中到一層中去: 因為所有的資料訪問操作現在都已經被DAO所代理,所以這個單獨的資料訪問層可以被看作可以是將資料訪問實現和其餘應用程式相互隔離的一層. 這樣的集中,使得應用程式可以更加容易的來維護和管理.
缺點:
- 增加了多餘的層:由於DAO在資料客戶端和資料來源之外多建立了一層物件,因而,需要對他進行設計和實現,來均衡這個設計模式的利弊. 但是,一般來說,採用此設計模式還是利大於弊的.
- **需要對類的相互繼承關係進行設計:**當使用工廠策略的時候,具體工廠類的繼承關係和由這些工廠類生成的產品需要進行設計和實現. 我們需要仔細考慮這些多付出的工作是否真的可以產生出來更高的靈活性. 使用這個策略會使設計變的更加複雜,然而,你可以先從工廠方法模式開始來實現這個策略,然後在需要的情況下再轉向抽象工廠
設計DaoFactory
首先,我們把DaoFactory設計成單例的【工廠有一個就夠了!】
public class DaoFactory {
private DaoFactory() {
}
private static final DaoFactory DAO_FACTORY = new DaoFactory();
//暴露公開方法獲取工廠物件
public static DaoFactory newInstance() {
return DAO_FACTORY;
}
}
複製程式碼
目前我們操作的是User,所以工廠造UserDao物件,而UserDao物件是JDBC版呢,還是XML版呢,我們通過配置檔案來定(這樣就更靈活了)!
- 在src目錄下加入配置檔案
- 注意:不要加""字串的符號!!!!!我就是這裡搞了很久!!!!
#class需要的是完整的物件名稱(包括包)
#userClass=zhongfucheng.dao.impl.UserImplDataBase
userClass=zhongfucheng.dao.impl.UserImplXML
複製程式碼
- 讀取配置檔案的資訊,建立相對應的UserDao物件,直接在建構函式做就行了(其實就是個初始化的操作罷了)
private static UserDao userDao = null;
private DaoFactory() {
try {
//讀取配置檔案的資訊
InputStream inputStream = DaoFactory.class.getClassLoader().getResourceAsStream("UserDao.properties");
Properties properties = new Properties();
properties.load(inputStream);
String userClass = properties.getProperty("userClass");
//利用反射機制建立相對應的物件
userDao = (UserDao) Class.forName(userClass).newInstance();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("讀取檔案失敗了!");
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException("反射失敗了!");
} catch (InstantiationException e) {
e.printStackTrace();
throw new RuntimeException("反射失敗了!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("反射失敗了!");
}
}
public static UserDao createUserDao() {
return userDao;
}
複製程式碼
在BusinessService層中用DaoFactory獲取UserDao物件
UserDao userDao = DaoFactory.newInstance().createUserDao();
複製程式碼
測試
**如果我們的mysql驅動版本太低,就出現以下的異常!**我們只需要下載新的mysql的jar包,匯入專案即可!
java.sql.SQLException: Feature not implemented Query:insert into guestbook (id,name,email,url,title,content,time) value(?,?,?,?,?,?,?) Parameters: [1, qwq,wqwq,qwqw,qw,qw, 2010-09-13]
複製程式碼
JDBC版的成功的效果如下:
XML版的成功效果如下:
總結
- 由於我們的Service層可能有多種實現【jdbc,xml】,如果我們直接是使用new具體的Service,那麼這耦合性就有點高了
- 於是我們有了工廠,工廠的目的就是解耦,我們通過配置檔案來建立具體的物件。
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,可以關注微信公眾號:Java3y