这篇博客接着上篇继续。
第三版:加入事务
Dbtuil新加入部分
public static void beginTransaction(Connection conn) {
try {
if (conn != null) {
if (conn.getAutoCommit()) {
conn.setAutoCommit(false); //手动提交
}
}
}catch(SQLException e) {}
}
public static void commitTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.commit();
}
}
}catch(SQLException e) {}
}
public static void rollbackTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.rollback();
}
}
}catch(SQLException e) {}
}
public static void resetConnection(Connection conn) {
try {
if (conn != null) {
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}else {
conn.setAutoCommit(true);
}
}
}catch(SQLException e) {}
}
IdGenerator
public static int generate(String tableName) {
//使用数据库的悲观锁for update
String sql = "select value from t_table_id where table_name=? for update";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
int value = 0;
try {
conn = DbUtil.getConnection();
//开始事务
DbUtil.beginTransaction(conn);
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, tableName);
rs = pstmt.executeQuery();
if (!rs.next()) {
throw new RuntimeException();
}
value = rs.getInt("value");
value++; //自加
modifyValueField(conn, tableName, value);
//提交事务
DbUtil.commitTransaction(conn);
}catch(Exception e) {
e.printStackTrace();
//回滚事务
DbUtil.rollbackTransaction(conn);
throw new RuntimeException();
}finally {
DbUtil.close(rs);
DbUtil.close(pstmt);
DbUtil.resetConnection(conn); //重置Connection的状态
DbUtil.close(conn);
}
return value;
}
ItemManagerImpl
public class ItemManagerImpl implements ItemManager {
private ItemDaoFactory factory = null;
public void addItem(Item item) {
//ItemDaoFactory factory = new ItemDaoFactory4Oracle();
//ItemDaoFactory factory = new ItemDaoFactory4MySql();
String className = XmlConfigReader.getInstance().getDaoFactory("item-dao-facotry");
try {
factory = (ItemDaoFactory)Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
ItemDao itemDao = factory.createItemDao();
Connection conn = null;
try {
conn = DbUtil.getConnection();
if (itemDao.findItemById(conn, item.getItemNo()) != null) {
throw new ApplicationException("物料代码已经存在,代码=" + item.getItemNo() + "");
}
itemDao.addItem(conn, item);
}catch(ApplicationException e) {
throw e;
}finally {
DbUtil.close(conn);
}
}
分析
在这一版中引入了事务。主要使用事务的是drp3.0中的id生成器。亮点在于drp3.6中ItemManagerIpl中对于事务的管理。视频中提出一个非常重要的观点,事务的边界在B层,所以在B层获取connection参数,然后传到d层,这样就能保证d层各个类所使用的cconnction是唯一的。
第四版
加入工厂方法
改写后的XmlConfigReader
private XmlConfigReader() {
SAXReader reader = new SAXReader();
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("sys-config.xml");
try {
Document doc = reader.read(in);
//取得jdbc相关配置信息
Element driverNameElt = (Element)doc.selectObject("/config/db-info/driver-name");
Element urlElt = (Element)doc.selectObject("/config/db-info/url");
Element userNameElt = (Element)doc.selectObject("/config/db-info/user-name");
Element passwordElt = (Element)doc.selectObject("/config/db-info/password");
//设置jdbc相关的配置
jdbcConfig.setDriverName(driverNameElt.getStringValue());
jdbcConfig.setUrl(urlElt.getStringValue());
jdbcConfig.setUserName(userNameElt.getStringValue());
jdbcConfig.setPassword(passwordElt.getStringValue());
System.out.println("读取jdbcConfig-->>" + jdbcConfig);
//取得DaoFactory信息
List daoFactorylist = doc.selectNodes("/config/dao-factory/*");
for (int i=0; i<daoFactorylist.size(); i++) {
Element daoFactoryElt = (Element)daoFactorylist.get(i);
String tagName = daoFactoryElt.getName();
String tagText = daoFactoryElt.getText();
System.out.println("读取DaoFactory-->>" + tagText);
//放入到Map中
daoFactoryMap.put(tagName, tagText);
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
ItemDaoFactory4Oracle
public ItemDao createItemDao() {
return new ItemDao4OracleImpl();
}
工厂所对应的产品
ItemDao4OracleImpl
public void delItem(Connection conn, String[] itemNos) {
// TODO Auto-generated method stub
}
分析
最大的亮点在于使用了工厂方法模式。与以前相比,不仅仅将数据库连接用的数据存入了xml文件也将工厂名字存入了xml文件,这样有利于工厂的创建。但缺点在于每种工厂只能对应一种产品。想创建一个新的产品就必须创建一个新的工厂,很麻烦。drp3.6。此外还有一点需要注意,因为使用了多层,所以不建议在中间层抓取异常。
第五版
抽象工厂版
抽象共厂在工厂方法的基础进行进一步改造。为了解决工厂方法不善于生产新产品的缺点,这次把抽象工厂所生产的对象也存入了xml文件。
简化后的XmlReader ,删去创建工厂部分
//懒汉式(延迟加载lazy)
private static XmlConfigReader instance = null;
private JdbcConfig jdbcConfig = new JdbcConfig();
private XmlConfigReader() {
SAXReader reader = new SAXReader();
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("sys-config.xml");
try {
Document doc = reader.read(in);
//取得jdbc相关配置信息
Element driverNameElt = (Element)doc.selectObject("/config/db-info/driver-name");
Element urlElt = (Element)doc.selectObject("/config/db-info/url");
Element userNameElt = (Element)doc.selectObject("/config/db-info/user-name");
Element passwordElt = (Element)doc.selectObject("/config/db-info/password");
//设置jdbc相关的配置
jdbcConfig.setDriverName(driverNameElt.getStringValue());
jdbcConfig.setUrl(urlElt.getStringValue());
jdbcConfig.setUserName(userNameElt.getStringValue());
jdbcConfig.setPassword(passwordElt.getStringValue());
System.out.println("读取jdbcConfig-->>" + jdbcConfig);
} catch (DocumentException e) {
e.printStackTrace();
}
}
public static synchronized XmlConfigReader getInstance() {
if (instance == null) {
instance = new XmlConfigReader();
}
return instance;
}
/**
* 返回jdbc相关配置
* @return
*/
public JdbcConfig getJdbcConfig() {
return jdbcConfig;
}
xml文件里
<beans>
<service-class>
<service id="com.bjpowernode.drp.basedata.manager.ItemManager" class="com.bjpowernode.drp.basedata.manager.ItemManagerImpl"/>
</service-class>
<dao-class>
<dao id="com.bjpowernode.drp.basedata.dao.ItemDao" class="com.bjpowernode.drp.basedata.dao.ItemDao4OracleImpl" />
<dao id="com.bjpowernode.drp.flowcard.dao.FlowCardDao" class="com.bjpowernode.drp.flowcard.dao.impl.FlowCardDaoImpl" />
</dao-class>
</beans>
实现抽象工厂
public class DefaultBeanFactory implements BeanFactory {
/*
* key=配置文件中的id值
* value=对应了改Id的对象
*/
private Map beansMap = new HashMap();
//系统缺省配置文件名称
private String beansConfigFile = "beans-config.xml";
private Document doc;
//如果直接new就采用缺省配置文件的名称beans-config.xml
public DefaultBeanFactory(){
loadConfigFile();
}
public DefaultBeanFactory(String beansConfigFile) {
throw new RuntimeException("此构造方法不支持!");
}
public DefaultBeanFactory(File beansConfigFile) {
throw new RuntimeException("此构造方法不支持!");
}
public DefaultBeanFactory(URL beansConfigFile) {
throw new RuntimeException("此构造方法不支持!");
}
public DefaultBeanFactory(InputStream is) {
throw new RuntimeException("此构造方法不支持!");
}
public synchronized Object getBean(String beanId) {
//如果存在相关对象实例,返回
if (beansMap.containsKey(beanId)) {
return beansMap.get(beanId);
}
Element beanElt = (Element)doc.selectSingleNode("//bean[@id=\"" + beanId + "\"]");
String className = beanElt.attributeValue("class");
Object bean = null;
try {
bean = Class.forName(className).newInstance();
//将创建好多的对象放到Map中
beansMap.put(beanId, bean);
} catch (Exception e) {
throw new RuntimeException();
}
return bean;
}
private void loadConfigFile() {
try {
doc = new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
} catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
新建servlet,在启动时创建对象
public class InitServlet extends HttpServlet {
@Override
public void init() throws ServletException {
//创建缺省工厂
BeanFactory beanFactory = new DefaultBeanFactory();
//将工厂设置到ServletContext中
this.getServletContext().setAttribute("beanFactory", beanFactory);
}
}
配置servlet的配置文件
<servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.bjpowernode.drp.util.servlet.InitServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
抽象servlet
itemManager = (ItemManagerImpl)beanFactory.getBean("itemManager");
ItemDao itemDao = (ItemDao)beanFactory.getBean("itemDao");
itemManager.setItemDao(itemDao);
特点分析
1把多种产品放到了xml,在要生产时根据xml文件内容随时读取。极具灵活性,是抽象工厂模式的特点2为了解决io操作频繁的问题将文件的读取放到了构造方法中3为了保证工厂只创建一次使用单例模式3为了避免一次性读取太多内容给系统造成负担,使用延迟加载的方法4将抽象工厂的创建放到servlet中,让servlet创建之初就将工厂要创建的所有对象都生产出来。
总结
drp中较为广泛地使用了单例模式和延迟加载。这其实就是缓存的思想。同时又用抽象工厂和servlet将要生产的对象在servlet产生之初就全部生产出来,极大地节约了内存和效率。使我对单例模式,抽象工厂和工厂方法有了进一步的认识。