實現基於接口編程的關鍵在於DAO是一個代理類, 所以DAO 不該該由用戶進行實例化, 應該由框架提供統一的工廠類用來獲取DAO. 工廠類中根據DAO類型生成對應的動態代理類返回用戶.sql
// Mapper工廠類(負責生成DAO的動態代理對象)
public class MapperFactory {
// SQL會話工廠類
private SqlSessionFactory sqlSessionFactory;
// 經過SQL會話工廠類實例化
public MapperFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
// 根據DAO類型獲取DAO的動態代理類
public <T> T getMapper(Class<T> clazz) {
SqlSession session = this.sqlSessionFactory.getSession();
return new MapperProxy(session).getMapper(clazz);
}
}
複製代碼
在獲取DAO時經過工廠類獲取, 此時獲取的是DAO的代理類.數據庫
UserDAO userDAO = new MapperFactory(sf).getMapper(UserDAO.class);
複製代碼
當調用DAO中的接口時, 會自動執行動態代理類中的invoke方法. 在invoke方法中執行數據庫操做便可.編程
// Mapper動態代理類
public class MapperProxy implements InvocationHandler {
// SQL會話
private SqlSession sqlSession;
// 經過SQL會話實例化
public MapperProxy(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
// 獲取動態代理類
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> clazz) {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, this);
}
// 執行接口時進入該方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 接口中方法名稱和SQL節點ID相同
String statementId = method.getName();
// 根據方法名稱便可獲取對應的SQL節點信息
MappedStatement ms = sqlSession.getConfig().getMappedStatement(statementId);
if (ms == null) {
throw new RuntimeException("無對應的SQL, id:" + statementId);
}
String type = ms.getStatementType();
Object param = (args != null) ? args[0] : null;
// 根據SQL類型執行對應的數據庫操做方法
if ("insert".equals(type)) {
return sqlSession.insert(statementId, param);
} else if ("update".equals(type)) {
return sqlSession.update(statementId, param);
} else if ("delete".equals(type)) {
return sqlSession.delete(statementId, param);
} else if ("select".equals(type)) {
return sqlSession.selectList(statementId, param);
}
return null;
}
}
複製代碼
測試bash
public static void main(String[] args) {
// 建立SQL會話工廠
SqlSessionFactory sf = new SqlSessionFactoryBean("*_mapper.xml").build();
MapperFactory factory = new MapperFactory(sf);
// 經過工廠類獲取DAO
UserDAO userDAO = factory.getMapper(UserDAO.class);
// 調用DAO中方法
int count = userDAO.insertUser(new User(1L, "zhangsan", 20, "sssss", "ok"));
List<User> userList = userDAO.selectUser();
// 輸出查詢結果
System.out.println(count);
for (User u : userList) {
System.out.println("| " + u.getId() + " | " + u.getUname() + " | ");
}
}
複製代碼