??xml version="1.0" encoding="utf-8" standalone="yes"?>
• Struts1要求Actioncȝ承一个抽象基cRStruts1的一个普遍问题是使用抽象cȝE而不是接口?
• Struts 2 Actioncd以实C个Action接口Q也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类?实现 常用的接口。Action接口不是必须的,M有execute标识的POJO对象都可以用作Struts2的Action对象?
U程模式:
• Struts1 Action是单例模式ƈ且必LU程安全的,因ؓ(f)仅有Action的一个实例来处理所有的h。单例策略限制了Struts1 Action能作的事Qƈ且要在开发时特别心。Action资源必须是线E安全的或同步的?
• Struts2 Action对象为每一个请求生一个实例,因此没有U程安全问题。(实际上,servlet容器l每个请求生许多可丢弃的对象,q且不会(x)D性能和垃圑֛攉题)
Servlet 依赖:
• Struts1 Action 依赖于Servlet API ,因ؓ(f)当一个Action被调用时HttpServletRequest ?HttpServletResponse 被传递给executeҎ(gu)?
• Struts 2 Action不依赖于容器Q允许Actionq容器单独被测试。如果需要,Struts2 Action仍然可以讉K初始的request和response。但是,其他的元素减或者消除了直接讉KHttpServetRequest ?HttpServletResponse的必要性?
可测?
• 试Struts1 Action的一个主要问题是executeҎ(gu)暴露了servlet APIQ这使得试要依赖于容器Q。一个第三方扩展Q-Struts TestCaseQ-提供了一套Struts1的模拟对象(来进行测试)?
• Struts 2 Action可以通过初始化、设|属性、调用方法来试Q?#8220;依赖注入”支持也ɋ试更容易?
捕获输入:
• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须l承一个基cR因为其他JavaBean不能用作ActionFormQ开发者经 常创建多余的cL莯入。动态BeanQDynaBeansQ可以作为创ZlActionForm的选择Q但是,开发者可能是在重新描q?创徏)已经?在的JavaBeanQ仍然会(x)D有冗余的javabeanQ?
• Struts 2直接使用Action属性作入属性,消除了对W二个输入对象的需求。输入属性可能是有自??属性的rich对象cd。Action属性能够通过 web面上的taglibs讉K。Struts2也支持ActionForm模式。rich对象cdQ包括业务对象,能够用作输入/输出对象。这U?ModelDriven Ҏ(gu)简化了taglib对POJO输入对象的引用?
表达式语aQ?
• Struts1 整合了JSTLQ因此用JSTL EL。这UEL有基本对象图遍历Q但是对集合和烦引属性的支持很弱?
• Struts2可以使用JSTLQ但是也支持一个更强大和灵zȝ表达式语aQ-"Object Graph Notation Language" (OGNL).
l定值到面QviewQ?
• Struts 1使用标准JSP机制把对象绑定到面中来讉K?
• Struts 2 使用 "ValueStack"技术,使taglib能够讉KD不需要把你的面QviewQ和对象l定h。ValueStack{略允许通过一pd名称相同但类型不同的属性重用页面(viewQ?
cd转换Q?
• Struts 1 ActionForm 属性通常都是Stringcd。Struts1使用Commons-Beanutilsq行cd转换。每个类一个{换器Q对每一个实例来说是不可配置的?
• Struts2 使用OGNLq行cd转换。提供基本和常用对象的{换器?
校验Q?
• Struts 1支持在ActionForm的validateҎ(gu)中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容Q但不能校验子对象?
• Struts2支持通过validateҎ(gu)和XWork校验框架来进行校验。XWork校验框架使用为属性类cd定义的校验和内容校验Q来支持chain校验子属?
Action执行的控Ӟ(x)
• Struts1支持每一个模块有单独的Request ProcessorsQ生命周期)Q但是模块中的所有Action必须׃n相同的生命周期?
• Struts2支持通过拦截器堆栈(Interceptor StacksQؓ(f)每一个Action创徏不同的生命周期。堆栈能够根据需要和不同的Action一起用?/pre>
]]>
--应用h|(x)在这个阶D,使用h里的当前值来更新每个lg的本地|q些值可能来自请求参敎ͼh的包头及(qing)cookie。在q个阶段的处理中Q组件可以往事g队列里加入某些事Ӟq些事g可在随后的处理阶D处?
--处理验证Q当每个lg的本地D更新后,在此阶段中LifeCycle对象?x)验证这些值的合法性。要求验证的lg必须提供验证逻辑的实现。作
为选择Q开发h员可以ؓ(f)一个组件注?个或者多个验证器。如果发现外部验证器Q那么还?x)应用这些外部验证器里的验证逻辑来验证本地倹{?
--更新模型|(x)只有当组件树(wi)中所有的lg的本地值都通过验证后,才有可能到达该阶Dc(din)在q个阶段中,LifeCycle更新呢应用的模型数据。组件在q个节点也可以排列事件?
--调用应用Q在q个阶段QJSF实现处理所有应用层ơ的旉?
--呈现响应Q在q个阶段QJSF实现相应发挥客L(fng)?
JSF的生命周期:(x)
恢复视图--应用h?-处理验证--呈现响应--调用应用E序--更新模型?
JSF的工作方式:(x)
JSF应用是通过处理由页面中lg处罚的事件来工作的。这些事件是qL(fng)动作引v的。(JSF是事仉动的Q?
--创徏FacesContext
--把控制权交给LifeCycle
--分六个阶D处理FacesContext
ajax原理Q?
-----一个异步无h的技术,主要是通过在客L(fng)览器内|的XMLHttpRequest对象Q发送和接收h?
XMLHttpRequest对象先把h发送给览器中内置的ajax引擎Q通过引擎转发l对应的服务器,q且引擎q要负责接收服务器的q回Q?
和服务器q行交互Q即时获取服务器的状态。还要负责把服务器的q回发送给客户端。客L(fng)通过XMLHttpRequest对象对返回结果进行解?
Http原理Q?
----最常见的网l传输协议。速度快,无状态?
----不管客户端用什么频率去h服务器的资源Q服务器只会(x)d应,而不?x)去保存客户端的M状?
Struts原理Q?
----web服务器启动的时候读取web.xml文档Q创建ActionServlet对象?
----当客L(fng)h发v是,ActionServlet拦截hQ截取特定的hQ获取请求的名称?
----然后dStrutsd配置文g,Ҏ(gu)h的名U读取相关信息,保存在moduleConfig对象?
----扑ֈ其中的ActionMapping和path属性,来进行请求是否匹配的判断
----如果发现有对应的pathQ则请求{到对应的ActionQƈ且创建ActionForm对象Q获取从h中传递来的参敎ͼ参C存在ActionForm中,调用Action的executeҎ(gu)
----ActionServlet接收Action处理完业务逻辑q回的结?--ActionForward对象
----然后在配|文件找到对应的forward路径Q将昄转发或者重定向到找到的路径?
Servlet MVC原理Q?
----服务器启动的时候读取web.xmlQ创建servlet对象?
----当客L(fng)发vh的时候,servlet负责拦截指定的请求,Ҏ(gu)h的方式是getq是post调用对象的doGet或者doPostҎ(gu)?
----doGetQdoPost中通过request或者response控制面的{发或者重定向
]]>
]]>
spring + hibernate 数据话持久层 [转]
spring + hibernate 数据话持久层Q{Q?br />
张利 发?br />
对于J2EE 应用E序而言Q事务的处理一般有两种模式Q?br />1Q 依赖特定事务资源的事务处理
q是应用开发中最常见的模式,即通过特定资源提供的事务机制进行事务管理?br /> 如通过JDBC、JTA 的rollback、commitҎ(gu)QHibernate Transaction 的rollback、commitҎ(gu){。这U方法大家已l相当熟(zhn)?br />2Q 依赖容器的参数化事务管?br />通过容器提供的集U式参数化事务机Ӟ实现事务的外部管理,如EJB 中的事务理模式?br /> 如,下面的EJB事务定义中,SessionBean MySession的doService?br />法定义ؓ(f)Required。也是_(d)当MySession.doServer Ҏ(gu)被某个线E调用时Q容器将此线E纳入事务管理容器,Ҏ(gu)调用q程中如果发生异常,当前事务被容器自动回滚Q如果方法正常结束,则容器将自动提交当前事务?br /><container-transaction >
<method >
<ejb-name>MySession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doService</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
容器理的参数化事务为程序开发提供了相当的灵zL,同时因ؓ(f)事务委托给容器q行理Q应用逻辑中无需再编写事务代码,大大节省了代码量Q特别是针对需要同时操作多个事务资源的应用Q,从而提高了生率。然而,使用EJB 事务理的代L(fng)当高昂,撇开EJB 容器不菲的h(hun)|EJB的学?fn)成本,部v、迁UR维护难度,以及(qing)容器本n带来的性能开销Q这往往意味着需要更高的g配置Q都l我们带来了相当的困惑。此时事务管理所带来的优势往往q不能抵消上面这些负面媄(jing)响?br />
Spring事务理能给我们带来什?
下面q段xml配置片断展示了Spring中的事务讑֮方式Q?br /><beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>org.gjt.mm.mysql.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost/sample</value>
</property>
<property name="username">
<value>user</value>
</property>
<property name="password">
<value>mypass</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTr
ansactionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
<bean id="userDAOProxy"
class="org.springframework.transaction.interceptor.Tran
sactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="get*">
PROPAGATION_REQUIRED,readOnly
</prop>
</props>
</property>
</bean>
</beans>
配置中包含了dataSourceQtransactionManager {资源定义。这些资源都Z个名为userDAOProxy 的TransactionProxyFactoryBean 服务Q 而userDAOProxy 则对包含实际数据逻辑的userDAOq行了事务性封装?br />可以看到Q在userDAOProxy ?transactionAttributes"属性中Q我们定义了针对userDAO 的事务策略,卛_所有名UCinsert 开始的Ҏ(gu)Q如UserDAO.insertUserҎ(gu)Q纳入事务管理范围。如果此Ҏ(gu)中抛出异常,则Spring
当前事务回滚,如果Ҏ(gu)正常l束Q则提交事务。而对所有名UCget 开始的Ҏ(gu)Q如UserDAO.getUser Ҏ(gu)Q则以只ȝ事务处理机制q行处理。(设ؓ(f)只读型事务,可以使持久层试Ҏ(gu)据操作进行优化,如对
于只M务Hibernate不执行flush操作Q而某些数据库q接池和JDBC 驱动也对只读型操作进行了特别化。)
l合上面q段x带来的感性认知,看看Spring 的事务管理机制与EJB 中事务管理有何不同,或者有何优ѝ这里自然有许多斚w可以比较Q不q,W者认为其中最为关键的两点是:(x)
1Q Spring可以Q意Java Class U_事务理
q里的UserDAO只是我们~写的一个普通Java ClassQ其中包含了一些基本的数据应用逻辑。通过SpringQ我们即可简单的实现事务的可配置化。也是_(d)我们可以随意为某个类的某个方法指定事务管理机制。与之对比,如果使用EJB容器提供的事务管理功能,我们不得不按照EJB规范~将UserDAO q行攚w,其转换Z个标准的EJB?br />2Q Spring事务理q不依赖特定的事务资源?br />EJB 容器必须依赖于JTA 提供事务支持。而Spring 的事务管理则支持JDBC、JTA {多U事务资源。这为我们提供了更多的选择Q从而也使得我们的系l部|更加灵zR?br /> 对Spring事务理机制q行单分析之后,我们结合持久层装的具体事务应用机Ӟ对Spring中的事务理q行更具实效的探讨?br /> 持久层封?br /> JDBC
Spring对JDBCq行了良好的装Q通过提供相应的模板和辅助c,在相当程度上降低了JDBC操作的复杂性。ƈ且得益于Spring良好的隔设计,JDBC装cd可以qSpring Context独立使用Q也是_(d)即ɾpȝq没有采用Spring作ؓ(f)l构性框Ӟ我们也可以单独用Spring的JDBC部分Qspring-dao.jarQ来改善我们的代码。作为对比,首先让我们来看一D传l的JDBC代码Q?br />Connection conn =null;
Statement stmt = null;
try {
conn = dataSource.getConnection();
stmt = con.createStatement();
stmt.executeUpdate("UPDATE user SET age = 18 WHERE id = 'erica'";
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException ex) {
logger.warn("Exception in closing JDBC Statement", ex);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
logger.warn("Exception in closing JDBC Connection", ex);
}
}
}
cM上面的代码非常常见。ؓ(f)了执行一个SQL语句Q我们必ȝ?2行代码,而其?1行与应用逻辑q无兌Qƈ且,q样的代码还?x)在pȝ其他地方Q也许是每个需要数据库讉K的地方)重复出现?br />于是Q大家开始寻找一些设计模式以改进如此的设计,Template模式的应用是其中一U典型的改进Ҏ(gu)。Spring的JDBC装Q很大一部分是借助Template模式实现Q它提供了一个优U的JDBC模板库,借助q个工具Q我们可以简单有效的对传l的JDBC~码方式加以改进。下面是借助Spring JDBC Template修改q的代码Q这D代码完成了与上面代码相同的功能?br />
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'";
可以看到Q两行代码完成了上面需?9行代码实现的功能。所有冗余的代码都通过合理的抽象汇集到了JdbcTemplate中。无需感叹Q借助Template模式Q我们大致也能实现这样一个模板,不过QSpring的设?br />者已l提前完成了q一步骤。org.springframework.jdbc.core.JdbcTemplate中包含了q个模板实现的代码,l过Spring设计组_ֿ设计Q这个实现可以算的上是模板应用的典范。特别是回调QCallBackQ的使用Q得整个模板结构清晰高效。值得一诅R?br />
Tips:实际开发中Q可以将代码中硬~码的SQL语句作ؓ(f)Bean的一个Stringcd属性,借助DI机制在配|文件中定义Q从而实现SQL的参数化配置?br />
再对上面的例子进行一些改q,通过PrepareStatement执行update操作以避免SQL
Injection 漏洞 9Q?br />JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate
.update(
"UPDATE user SET age = ? WHERE id = ?",
new PreparedStatementSetter() {
public void setValues(PreparedStatementSetter ps)
throws SQLException {
ps.setInt(1, 18);
ps.setString(2, "erica";
}
}
);
可以看到Q上面引用了updateҎ(gu)的另一个版本,传入的参数有两个Q第一个用于创?br />PreparedStatement的SQL。第二个参数是ؓ(f)PreparedStatement讑֮参数的PreparedStatementSetter?br />W二个参数的使用Ҏ(gu)比较独到Q我们动态新Z一个PreparedStatementSetterc,q实Cq个抽象cȝsetValuesҎ(gu)。之后将q个cȝ引用作ؓ(f)参数传递给update。update接受参数之后Q即可调用第二个参数提供的方法完成PreparedStatement的初始化?br />Spring JDBC Template中大量用了q样的Callback机制Q这带来了极强的灉|性和扩展性?br />上面演示了updateҎ(gu)的用(同样的操作适用于update、insert、deleteQ。下面是一个查询的CZ?br />final List userList = new ArrayList();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate
.query(
"SELECT name, sex, address FROM user WHERE age > 18",
9 SQL InjectionQ SQL语句中直接引入参数D导致的pȝ漏洞Q具体请参见以下论文Q?br />http://www.governmentsecurity.org/articles/SQLInjectionModesofAttackDefenceandWhyItMatters.php
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getString("name");
user.setSex(rs.getString("sex");
user.setAddress(rs.getString("address");
userList.add(product);
}
}
);
q里传入queryҎ(gu)的有两个参数Q第一个是Select查询语句Q第二个是一个RowCallbackHandler实例Q我们通过RowCallbackHandler对Select语句得到的每行记录进行解析,qؓ(f)其创Z个User数据对象。实C手动的OR映射。此外,我们q可以通过JdbcTemplate.callҎ(gu)调用存储q程。query、updateҎ(gu)q有其他很多不同参数版本的实玎ͼ具体调用Ҏ(gu)请参见SpringJavaDoc?br />
JdbcTemplate与事?br />
上例中的JdbcTemplate操作采用的是JDBC默认的AutoCommit模式Q也是说我们还无法保证数据操作的原子性(要么全部生效Q要么全部无效)Q如Q?br />JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'";
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'";
׃采用了AutoCommit模式Q第一个update操作完成之后被自动提交,数据库中”erica”对应的记录已经被更斎ͼ如果W二个操作失败,我们无法使得整个事务回滚到最初状态。对于这个例子也许无关紧要,但是对于一个金融帐务系l而言Q这L(fng)问题导致致命错误?br />Z实现数据操作的原子性,我们需要在E序中引入事务逻辑Q在JdbcTemplate中引入事务机Ӟ在Spring中有两种方式Q?br />1Q 代码控制的事务理
2Q 参数化配置的事务管?br />下面p两种方式q行介绍?br />u 代码控制的事务管?br />首先Q进行以下配|,假设配置文g为(Application-Context.xmlQ:(x)
<beans>
<bean id="dataSource"
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransac
tionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
</beans>
配置中包含了三个节点:
Ø dataSource
q里我们采用了apache dhcplg提供的DataSource实现Qƈ为其配置了JDBC驱动、数据库URL、用户名和密码等参数?br />Ø transactionManager
针对JDBC DataSourcecd的数据源Q我们选用了DataSourceTransactionManager作ؓ(f)事务理lg?br />如果需要用基于容器的数据源(JNDIQ,我们可以采用如下配置Q?br />SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTrans
actionManager"
/>
Ø userDAO
x了一个UserDAO BeanQƈ为其指定了dataSource和transactionManger资源?br />UserDAO对应的代码如下:(x)
public class UserDAO {
private DataSource dataSource;
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
public DataSource executeTestSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertUser() {
TransactionTemplate tt =
new TransactionTemplate(getTransactionManager());
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update(
"insert into users (username) values ('xiaxin');";
jt.update(
"insert into users (id,username) values(2,
'erica');";
return null;
}
});
}
}
可以看到Q在insertUserҎ(gu)中,我们引入了一个新的模板类Q?br />org.springframework.transaction.support.TransactionTemplate?br />TransactionTemplate装了事务管理的功能Q包括异常时的事务回滚,以及(qing)操作成功后的事务提交。和JdbcTemplate一P它得我们无需在琐的try/catch/finally代码中徘徊?br />在doInTransaction中进行的操作Q如果抛出未捕获异常被自动回滚Q如果成功执行, 则将被自动提交?br />q里我们故意刉了一些异常来观察数据库操作是否回滚(通过在第二条语句中更新自增ID字段故意触发一个异常)Q?br />~写一个简单的TestCase来观察实际效果:(x)
InputStream is = new FileInputStream("Application-Context.xml";
XmlBeanFactory factory = new XmlBeanFactory(is);
UserDAO userDAO = (UserDAO) factory.getBean("userDAO";
userDAO.insertUser();
怿大家多少觉得上面的代码有点凌乱,Callbackcȝ~写g也有(zhn)于日常的编E习(fn)惯(虽然W者觉得这一Ҏ(gu)比较有趣Q因为它巧妙的解决了W者在早期自行开发数据访问模板中曄遇到的问题)。如何进一步避免上面这些问题?Spring 的容器事务管理机制在q里即体现出其强大的能量。u 参数化配|的事务理在上面的Application-Context.xml增加一个事务代理(UserDAOProxyQ配|,同时Q由于事务由容器理QUserDAO不再需要TransactionManager讑֮Q将其移除:(x)
<bean id="UserDAOProxy"
class="org.springframework.transaction.interceptor.Transac
tionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
上面的配|中QUserDAOProxy节点配置了一个针对userDAO bean的事务代理(由target属性指定)。通过transactionAttributes属性,我们指定了事务的理{略Q即Ҏ(gu)有以insert开头的Ҏ(gu)q行事务理Q如果被理Ҏ(gu)抛出异常Q则自动回滚Ҏ(gu)中的事务Q如果成功执行,则在Ҏ(gu)完成之后q行事务提交。另一斚w对于其他Ҏ(gu)Q通过通配W?表示Q,则进行只M务管理,以获得更好的性能。与之对应U(ku)serDAO.insertUser的代码修改如下:(x)
public void insertUser(RegisterInfo regInfo) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update("insert into users (username) values ('xiaxin');";
jt.update("insert into users (id,username) values (2,'erica');";
}
试代码修改如下Q?br />InputStream is = new FileInputStream("Application-Context.xml";
XmlBeanFactory factory = new XmlBeanFactory(is);
//注意q里通过代理Bean"userDAOProxy"获得引用Q而不是直接getBean(“userDAO?
//此外q里q存在一个有兛_制{型的潜在问题Q请参见Hibernate in Spring一节后
//关于强制转型的补充描q?br />UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy";
userDAO.insertUser();
可以看到QinsertUser变得非常z。数据逻辑清晰可见Q对比前面代码控制的事务理Q以?qing)传l的JDBC操作Q相信大家会(x)有一些霍然开朗的感觉。细心的读者会(x)_(d)q只不过代码{Ud了配|文Ӟq没有减太多的工作量。这点区别也许ƈ不重要,从应用维护的角度而言Q配|化的事务管理显然更具优ѝ何况,实际开发中Q如果前期设计细_(d)Ҏ(gu)的事务特性确定之后一般不?x)发生大的变动,之后频繁的维护过E中Q我们只需面对代码中的数据逻辑卛_。上面我们结合JdbcTemplate介绍了Spring中的模板操作以及(qing)事务理机制。Spring作ؓ(f)一个开攑ּ的应用开发^台。同时也针对其他lg提供了良好的支持。在持久层,Spring提供面向了Hibernate、ibatis和JDO的模板实玎ͼ同样Q这些实C为我们的开发提供了强有力的支持?br />下面我们hibernate、ibatisq两U主持久层框架在Spring中的使用q行介绍。至于JDOQ由于实际开发中使用q不q泛Q实际上W者觉得JDO前景堪忧Q,q里也就不重点介l,有兴的读者可参见Spring-Reference中的相关章节?br />SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
Hibernate in Spring
Hibernate在开源的持久层框架中无疑是近期最为鲜亮的角色Q其作者甚臌邀(g)请加?br />新版EJB设计工作之中Q见Hibernate设计的精彩脓(chung)切。关于Hibernate的用,在笔?br />的另外一文档中q行了探讨:(x)
《Hibernate开发指南》?img alt="::URL::" hspace="2" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" />http://www.xiaxin.net/Hibernate_DEV_GUIDE.rar?/font>
下面主要Hibernate在Spring中的应用加以介绍Q关于Hibernate本n׃多加?br />q?br />另外考虑到Spring对容器事务的良好支持Q笔者徏议在ZSpring Framework的应
用开发中Q尽量用容器管理事务,以获得数据逻辑代码的最?jng)_L。下面的介绍中,?br />略过代码控制的事务管理部分,而将重点攑֜参数化的容器事务理应用。代码事务理
实现原理与上面JdbcTemplate中基本一_(d)感兴的读者可以参见Spring-Reference?br />的相兛_宏V?br />Zz,我们q是沿用上面的示例。首先,针对HibernateQ我们需要进行如下配|:(x)
Hibernate-Context.xml:
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean"
>
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>net/xiaxin/dao/entity/User.hbm.xml</value>
</list>
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
net.sf.hibernate.dialect.SQLServerDialect
</prop>
<prop key="hibernate.show_sql">
true
</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionMana
ger">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAOProxy"
class="org.springframework.transaction.interceptor.TransactionPro
xyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
</property>
</bean>
</beans>
与上面JDBC中的配置相对比,区别主要在于Q?br />1Q SessionFactory的引?br />Hibernate中通过SessionFactory创徏和维护Session。Spring对SessionFactory的配|也q行了整合,无需再通过Hibernate.cfg.xml对SessionFactoryq行讑֮?br />SessionFactory节点的mappingResources属性包含了映射文g的\径,list节点下可配置多个映射文g?br />hibernateProperties节点则容U了所有的属性配|?br />可以对应传统的Hibernate.cfg.xml文gl构对这里的SessionFactory配置q行解读?br />2Q 采用面向Hibernate的TransactionManager实现Q?br />org.springframework.orm.hibernate.HibernateTransactionManag
er
可以看到Q对于事务管理配|,基本与上一章节中相同。对应刚才的Users表,建立如下映射c:(x)
User.java:
/**
* @hibernate.class table="users"
*/
public class User {
public Integer id;
public String username;
public String password;
/**
* @hibernate.id
* column="id"
* type="java.lang.Integer"
* generator-class="native"
*/
public Integer getId() {
return id;
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
}
public void setId(Integer id) {
this.id = id;
}
/**
* @hibernate.property column="password" length="50"
*/
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
/**
* @hibernate.property column="username" length="50"
*/
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
上面的代码中Q通过xdoclet指定了类/表;属?字段的映关p,通过xdoclet anttask 我们可以Ҏ(gu)代码生成对应的user.hbm.xml文g。具体细节请参见《hibernate开发指南》一文?br />下面是生成的user.hbm.xmlQ?br /><hibernate-mapping>
<class
name="net.xiaxin.dao.entity.User"
table="users"
dynamic-update="false"
dynamic-insert="false"
>
<id
name="id"
column="id"
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
type="java.lang.Integer"
>
<generator class="native">
</generator>
</id>
<property
name="password"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="password"
length="50"
/>
<property
name="username"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="username"
length="50"
/>
</class>
</hibernate-mapping>
UserDAO.java:
public class UserDAO extends HibernateDaoSupport implements IUserDAO
{
public void insertUser(User user) {
getHibernateTemplate().saveOrUpdate(user);
}
}
看到q段代码惛_?x)有点诧异,g太简单了一点……,不过q已l够。短短一行代码我们已l实C与上一章中CZ相同的功能,q也正体CSpring+Hibernate的威力所在?br />上面的UserDAO实现了自定义的IUserDAO接口Q这里的IUserDAO接口仅包含insertUserҎ(gu)的定义,不过除此之外Q它q有另一层含义,见下面的代码试部分Q,
q扩展了抽象c:(x)
HibernateDaoSupport
HibernateSupport实现了HibernateTemplate和SessionFactory实例的关联。与JdbcTemplatecMQHibernateTemplate对Hibernate Session操作q行了封装,而HibernateTemplate.executeҎ(gu)则是一装机制的核心,感兴的读者可?br />研究一下其实现机制。借助HibernateTemplate我们可以q每次数据操作必须首先获得Session实例、启动事务、提?回滚事务以及(qing)烦杂的try/catch/finally的繁琐操作。从而获得以上代码中_ֹ集中的逻辑呈现效果?br />Ҏ(gu)下面q段实现了同样功能的Hibernate原生代码Q想必更有体?x)?x)
Session session
try {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory =
config.buildSessionFactory();
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setName("erica";
user.setPassword("mypass";
session.save(user);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
tx.rollback();
}finally{
session.close();
}
试代码Q?br />InputStream is = new FileInputStream("Hibernate-Context.xml";
XmlBeanFactory factory = new XmlBeanFactory(is);
IUserDAO userDAO = (IUserDAO)factory.getBean("userDAOProxy";
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
User user = new User();
user.setUsername("erica";
user.setPassword("mypass";
userDAO.insertUser(user);
q段代码gq没有什么特D,但有一个细微之处:(x)
IUserDAO userDAO = (IUserDAO)factory.getBean("userDAOProxy";
q里q没有直接用UserDAO对获得的Bean实例q行强制转型。这与上面JdbcTemplate的测试代码不同。ƈ非完全出自设计上的考虑Q这里情冉|些特D,我们可以试一下用UserDAOcdbean实例q行强制转型Q不q将得到一个ClassCastExceptionQ程序异怸止?br />Z么会(x)出现q样的问题?是不是只有在使用Hibernate才会(x)出现q样的问题?事实q如此Q如果对上面ZJdbcTempate的UserDAOq行攚w,使之实现IUserDAO接口Q同L(fng)问题也将?x)出现。IUserDAO接口本n非常单(仅包含一个insertUserҎ(gu)的定义)Q显然也不是D异常的原因所在。原因在于Spring的AOP实现机制Q前面曾l提?qing),Spring中的事务理实际上是Z动态AOP机制实现Qؓ(f)了实现动态AOPQSpring在默认情况下?x)用Java DynamicProxyQ但是,Dynamic Proxy要求其代理的对象必须实现一个接口,该接口定义了准备q行代理的方法。而对于没有实CQ何接口的Java ClassQ需要采用其他方式,Spring通过CGLib10实现q一功能?br />当UserDAO没有实现M接口Ӟ如JdbcTemplateCZ中)。Spring通过CGLib对UserDAOq行代理Q此时getBeanq回的是一个承自UserDAOcȝ子类实例Q可以通过UserDAO对其强制转型。而当UserDAO实现了IUserDAO接口之后QSpring通过JavaDynamic Proxy机制实现代理功能Q此时返回的BeanQ是通过java.lang.reflect.Proxy.newProxyInstanceҎ(gu)创徏的IUserDAO接口的一个代理实玎ͼq个实例实现了IUserDAO接口Q但与UserDAOcdl没有承关p,因此无法通过UserDAO强制转型。由于此问题牉|到较为底层的代理机制实现原理Q下面的AOP章节中我们再q行详细探讨?br />实际开发中Q应该面向接口编E,通过接口来调用Bean提供的服务?br />10 CGLib可以在运行期对Class行ؓ(f)q行修改。由于其功能强大Q性能ZQ常常被作ؓ(f)Java Dynamic Proxy
之外的动态Proxy模式的实现基。在Spring、Hibernate中都用到了CGLibcd?/td>
]]>
1.如果sql语句写在映射文g?如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="com.jgcgov.model.Contract" table="CONTRACT" schema="JGCUSER">
<id name="contractNo" type="string">
<column name="CONTRACT_NO" length="11" />
<generator class="assigned" />
</id>
............
<set name="TbTaxpayment2104Add" table="TB_TAXPAYMENT_2104_ADD" cascade="all">
<key column="CONTRACT_NO"></key>
<one-to-many class="com.jgcgov.model.TbTaxpayment2104Add" />
</set>
</class>
<!-- 查询合同的计E金额百分比-->
<sql-query name="contractPrealarm">
<![CDATA[
select con.CONTRACT_NO as contractNo,con.REGISTER_DATE as registerDate,
con.CONSTRUCT_UINT as constructUint,trunc(con.WORKLOAD*10000,2) as workload,
trunc(con1.TaxNum,2) as taxnum,trunc(con1.conPercent,1) as conPercent,
null as attribute7,null as attribute8,null as attribute9,null as attribute10
from CONTRACT con,(
select con.CONTRACT_NO as contractNo,sum(nvl(tb2104.TAX_BASE,0)/(con.WORKLOAD*100)) as conPercent,
sum(nvl(tb2104.TAX_BASE,0)) as TaxNum
from CONTRACT con ,Jgctax.TB_TAXPAYMENT_2104_ADD tb2104
where con.REGISTER_DATE >= :conBeg
and con.REGISTER_DATE <= :conEnd
and con.CONTRACT_NO = tb2104.contract_No(+)
and nvl(tb2104.OP_DATE,to_date('1900-01-01','yyyy-MM-dd')) <= :taxDate
and nvl(con.WORKLOAD,0)<>0
group by con.CONTRACT_NO
having sum(nvl(tb2104.TAX_BASE,0)/(con.WORKLOAD*100)) >= :percent) con1
where con.CONTRACT_NO=con1.contractNo
]]>
<return alias="con" class="com.jgcgov.model.HibernateSqlResult">
<return-property name="attribute1" column="contractNo" />
<return-property name="attribute2" column="registerDate" />
<return-property name="attribute3" column="constructUint" />
<return-property name="attribute4" column="workload" />
<return-property name="attribute5" column="taxnum" />
<return-property name="attribute6" column="conPercent" />
<return-property name="attribute7" column="attribute7" />
<return-property name="attribute8" column="attribute8" />
<return-property name="attribute9" column="attribute9" />
<return-property name="attribute10" column="attribute10" />
</return>
</sql-query>
</hibernate-mapping>
可以q样分页:
/***************************************************************************
* * 函数? getPrealarm * ?? conBeg,conEnd,taxDate,operatorStr,percent *
* conBeg---合同起始旉 * conEnd---合同l束旉 * taxDate---计税截止旉 * operatorStr---q算W?*
* percent---计税占合同额癑ֈ?* ?? List * 功能描述: 得到计税占合同额癑ֈ?* 全局变量: * 调用模块: * 作?
*
**************************************************************************/
}
/**分页操作
* 使用hql 语句q行操作
* @param offset
* @param length
* @return List
*/
public List getListForPage(int offset,int length,Date conBeg, Date conEnd, Date taxDate,
Float percent) {
final int offset3 = offset;
final int length3 = length;
final Date conBeg3 = conBeg;
final Date conEnd3 = conEnd;
final Date taxDate3 = taxDate;
final Float percent3 = percent;
List list = getHibernateTemplate().executeFind(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
Query query = session.getNamedQuery("contractPrealarm").setFirstResult(offset3).setMaxResults(length3);
query.setDate(0,conBeg3);
query.setDate(1,conEnd3);
query.setDate(2,taxDate3);
query.setFloat(4,percent3.floatValue());
List list = query.list();
return list;
}
});
return list;
}
/**
* 获得记录的M?br /> */
public int getCountForPage(){
List list = getHibernateTemplate().find(hql3);
int count = ((Integer)list.get(0)).intValue();
return count;
}
/**
* 获得分页cȝ对象
* SimplePager(昄内容,记录M?面最大个?当前?
*/
public Pageable getPageable(int offset,int length,Date conBeg, Date conEnd, Date taxDate,
Float percent,int currentPage){
final int offset1 = offset;
final int length1 = length;
final int currentPage1 = currentPage;
final int count = getCountForPage();
List list = getListForPage(int offset,int length,Date conBeg, Date conEnd, Date taxDate,
Float percent);
Pageable pageable = new SimplePager(list,count,length1,currentPage1);
return pageable;
}
2.直接写在javacM,则可以用session的creatQuery()q行分页,具体如下:
private static String hql3 = "select count(*) from Jgcuser as user order by user.id ";
private static String hql4 = "select u from Jgcuser as u order by u.id ";
/**分页操作
* 使用hql 语句q行操作
* @param offset
* @param length
* @return List
*/
public List getListForPage(int offset,int length) {
final int offset3 = offset;
final int length3 = length;
List list = getHibernateTemplate().executeFind(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
List list = session.createQuery(hql4).setFirstResult(offset3).setMaxResults(length3).list();
return list;
}
});
return list;
}
/**
* 获得记录的M?br /> */
public int getCountForPage(){
List list = getHibernateTemplate().find(hql3);
int count = ((Integer)list.get(0)).intValue();
return count;
}
/**
* 获得分页cȝ对象
* SimplePager(昄内容,记录M?面最大个?当前?
*/
public Pageable getPageable(int offset,int length,int currentPage){
final int offset1 = offset;
final int length1 = length;
final int currentPage1 = currentPage;
final int count = getCountForPage();
List list = getListForPage(offset1,length1);
Pageable pageable = new SimplePager(list,count,length1,currentPage1);
return pageable;
}