学习改造代码2

这篇博客接着上篇继续。

第三版:加入事务

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产生之初就全部生产出来,极大地节约了内存和效率。使我对单例模式,抽象工厂和工厂方法有了进一步的认识。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值