??xml version="1.0" encoding="utf-8" standalone="yes"?>
Java提供了SAX和DOM两种方式用于解析XML,但即便如?要读写一个稍微复杂的XML,也不是一件容易的?
二、XMLBean?/font>
Hibernate已经成ؓ目前行的面向Java环境的对?关系数据库映工?在Hibernate{对?关系数据库映工具出C?Ҏ?
库的操作是通过JDBC来实现的,Ҏ据库的Q何操?开发h员都要自己写SQL语句来实?
对象/关系数据库映工具出现后,Ҏ据库的操作{成对JavaBean的操?极大方便了数据库开?
所以如果有一个类似的工具能够实现对XML的读写{成对JavaBean的操?会化XML的读?即对XML不熟悉的开发h员也能方便地d
XML. q个工具是XMLBean.
三、准备XMLBean和XML文档
XMLBean是Apache的一个开源项?可以?a >http://www.apache.org下蝲,最新的版本?.0. 解压后目录如?
xmlbean2.0.0
另外q要准备一个XML文档(customers.xml),
在本文的例子?我们对q个文档q行d操作. 文档源码如下:
<?xml version="1.0" encoding="UTF-8"?>
q是一个客L数据模型,每个客户都有客户~号(ID),姓名,性别(gender),电话L(phoneNumber)和地址,其中地址有两?
首要地址(PrimaryAddress)和帐单地址(BillingAddress),每个地址有邮~?地址1,和地址2l成.其中帐单地址q有收g?
(receiver).此外,q要准备一个配|文?文g名customer.xsdconfig),q个文g的作用我后面会讲,它的内容如下:
<xb:namespace>
</xb:config>
四、XMLBean使用步骤
和其他面向Java环境的对?关系数据库映工L使用步骤一?在正式用XMLBean?我们要作两个准备.
1. 生成XML Schema文g
什么是XML Schema文g? 正常情况?每个XML文g都有一个Schema文g,XML
Schema文g是一个XML的约束文?它定义了XML文g的结构和元素.以及对元素和l构的约?
通俗地讲,如果说XML文g是数据库里的记录,那么Schema是表结构定?
Z么需要这个文?
XMLBean需要通过q个文g知道一个XML文g的结构以及约?比如数据cd{?
利用q个Schema文g,XMLBean会产生一pd相关的Java Classes来实现对XML的操?
而作为开发h?则是利用XMLBean产生的Java
Classes来完成对XML的操作而不需要SAX或DOM.怎样产生q个Schema文g?
如果对于熟悉XML的开发h?可以自己来写q个Schema文g,对于不熟悉XML的开发h?可以通过一些工h完成.比较有名的如XMLSPY?
Stylus Studio都可以通过XML文g来生成Schema文g. 加入我们已经生成q个Schema文g(customer.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:complexType name="primaryAddressType">
2. 利用scomp来生成Java Classes
scomp是XMLBean提供的一个编译工?它在bin的目录下. 通过q个工具,我们可以以上的Schema文g生成Java Classes.scomp的语法如?-
scomp [options] [dirs]* [schemaFile.xsd]* [service.wsdl]* [config.xsdconfig]*
主要参数说明:
-src [dir] -- 生成的Java Classes存放目录
-srconly -- 不编译Java Classes,不生Jar文g
-out [jarFileName] -- 生成的Jar文g,~省是xmltypes.jar
-compiler -- Java~译器的路径,即Javac的位|?/font>
schemaFile.xsd -- XML Schema文g位置
config.xsdconfig -- xsdconfig文g的位|? q个文g主要用来制定生成的Java Class的一些文件名规则和Package的名U?在本?package是sample.xmlbean
在本?我是q样q行?
scomp -src build\src -out build\customerXmlBean.jar schema\customer.xsd
q个命o行的意思是告诉scomp生成customerXmlBean.jar,攑֜build目录?同时生成源代码放在build\src?
Schema文g是customer.xsd,xsdconfig文g是customer.xsdconfig.其实,
生成的Java源代码没有多大作?我们要的是jar文g.我们先看一下build\src\sample\xmlbean下生成的Classes.
CustomersDocument.java -- 整个XML文档的Java Class映射
CustomerType.java -- 节点sustomer的映?/font>
AddressType.java -- 节点address的映?/font>
BillingAddressType.java -- 节点billingAddress的映?/font>
PrimaryAddressType.java -- 节点primaryAddress的映?/font>
好了,到此我们所有的准备工作已经完成? 下面开始进入重?利用刚才生成的jar文gdXML.
五、利用XMLBean读XML文g
新徏一个Java Project,XMLBean2.0.0\lib\下的Jar文g和刚才我们生成的customerXmlBean.jar加入到Project的ClassPath.
新徏一个Java Class: CustomerXMLBean. 源码如下:
package com.sample.reader;
import java.io.File;
public void customerReader() {
}
q行?参看输出l果:
Customer#0
Customer#1
怎么?是不是很L? XMLBean的威?
六、利用XMLBean写XML文g
利用XMLBean创徏一个XML文档也是一件轻而易丄?我们再增加一个Method,
L一下的Java Class:
public void createCustomer() {
// Add new BillingAddress
File xmlFile = new File(filename);
}
修改main method.
public static void main(String[] args) {
q行,打开customers_new.xml:
<?xml version="1.0" encoding="UTF-8"?>
七、利用XMLBean修改XML文g
我们再增加一个Method:
public void updateCustomer(int id,String lastname) {
main method:
public static void main(String[] args) {
q行之后,我们会看到客户~号?的客Llastname已经改ؓlast.
八、利用XMLBean删除一个customer
再增加一个Method:
public void deleteCustomer(int id) {
for (int i = 0; i < customers.length; i++) {
main method:
public static void main(String[] args) {
q行,我们会看到客户~号?的客L资料已经被删?
九、查询XML
除了本文在以上讲q的,利用XMLBean能轻L村֮成XML的读写操作外,l合XPath和XQuery,XMLBeanq能完成象SQL查询数据库一h便地查询XML数据. 关于XML查询以及如何创徏XML数据? 我将在另一文章里讨论.
十、结束语
XMLBean能帮助我们轻易读写XML,q将有助于我们降低XML的学习和使用,有了q个基础,开发h员将为学习更多地XML相关技术和Web Services,JMS{其他J2EE技术打下良好地基础.
]]>
+---bin
+---docs
+---lib
+---samples
+---schemas
<Customers>
<customer>
<id>1</id>
<gender>female</gender>
<firstname>Jessica</firstname>
<lastname>Lim</lastname>
<phoneNumber>1234567</phoneNumber>
<address>
<primaryAddress>
<postalCode>350106</postalCode>
<addressLine1>#25-1</addressLine1>
<addressLine2>SHINSAYAMA 2-CHOME</addressLine2>
</primaryAddress>
<billingAddress>
<receiver>Ms Danielle</receiver>
<postalCode>350107</postalCode>
<addressLine1>#167</addressLine1>
<addressLine2>NORTH TOWER HARBOUR CITY</addressLine2>
</billingAddress>
</address>
</customer>
<customer>
<id>2</id>
<gender>male</gender>
<firstname>David</firstname>
<lastname>Bill</lastname>
<phoneNumber>808182</phoneNumber>
<address>
<primaryAddress>
<postalCode>319087</postalCode>
<addressLine1>1033 WS St.</addressLine1>
<addressLine2>Tima Road</addressLine2>
</primaryAddress>
<billingAddress>
<receiver>Mr William</receiver>
<postalCode>672993</postalCode>
<addressLine1>1033 WS St.</addressLine1>
<addressLine2>Tima Road</addressLine2>
</billingAddress>
</address>
</customer>
</Customers>
<xb:package>sample.xmlbean</xb:package>
</xb:namespace>
<xs:schema xmlns:xs=" elementFormDefault="qualified">
<xs:element name="Customers">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="customer"
type="customerType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="customerType">
<xs:sequence>
<xs:element name="id" type="xs:int"/>
<xs:element name="gender" type="xs:string"/>
<xs:element name="firstname" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
<xs:element name="phoneNumber" type="xs:string"/>
<xs:element name="address" type="addressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="primaryAddress" type="primaryAddressType"/>
<xs:element name="billingAddress" type="billingAddressType"/>
</xs:sequence>
</xs:complexType>
<xs:sequence>
<xs:element name="postalCode" type="xs:string"/>
<xs:element name="addressLine1" type="xs:string"/>
<xs:element name="addressLine2" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="billingAddressType">
<xs:sequence>
<xs:element name="receiver" type="xs:string"/>
<xs:element name="postalCode" type="xs:string"/>
<xs:element name="addressLine1" type="xs:string"/>
<xs:element name="addressLine2" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
-compiler C:\jdk142_04\bin\javac customer.xsdconfig
import sample.xmlbean.*;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.xmlbeans.XmlOptions;
public class CustomerXMLBean {
private String filename = null;
public CustomerXMLBean(String filename) {
super();
this.filename = filename;
}
try {
File xmlFile = new File(filename);
CustomersDocument doc = CustomersDocument.Factory.parse(xmlFile);
CustomerType[] customers = doc.getCustomers().getCustomerArray();
for (int i = 0; i < customers.length; i++) {
CustomerType customer = customers[i];
println("Customer#" + i);
println("Customer ID:" + customer.getId());
println("First name:" + customer.getFirstname());
println("Last name:" + customer.getLastname());
println("Gender:" + customer.getGender());
println("PhoneNumber:" + customer.getPhoneNumber());
// Primary address
PrimaryAddressType primaryAddress = customer.getAddress().getPrimaryAddress();
println("PrimaryAddress:");
println("PostalCode:" + primaryAddress.getPostalCode());
println("AddressLine1:" + primaryAddress.getAddressLine1());
println("AddressLine2:" + primaryAddress.getAddressLine2());
// Billing address
BillingAddressType billingAddress = customer.getAddress().getBillingAddress();
println("BillingAddress:");
println("Receiver:" + billingAddress.getReceiver());
println("PostalCode:" + billingAddress.getPostalCode());
println("AddressLine1:" + billingAddress.getAddressLine1());
println("AddressLine2:" + billingAddress.getAddressLine2());
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void println(String str) {
System.out.println(str);
}
public static void main(String[] args) {
String filename = "F://JavaTest//Eclipse//XMLBean//xml//customers.xml";
CustomerXMLBean customerXMLBean = new CustomerXMLBean(filename);
customerXMLBean.customerReader();
}
Customer ID:1
First name:Jessica
Last name:Lim
Gender:female
PhoneNumber:1234567
PrimaryAddress:
PostalCode:350106
AddressLine1:#25-1
AddressLine2:SHINSAYAMA 2-CHOME
BillingAddress:
Receiver:Ms Danielle
PostalCode:350107
AddressLine1:#167
AddressLine2:NORTH TOWER HARBOUR CITY
Customer ID:2
First name:David
Last name:Bill
Gender:male
PhoneNumber:808182
PrimaryAddress:
PostalCode:319087
AddressLine1:1033 WS St.
AddressLine2:Tima Road
BillingAddress:
Receiver:Mr William
PostalCode:672993
AddressLine1:1033 WS St.
AddressLine2:Tima Road
try {
// Create Document
CustomersDocument doc = CustomersDocument.Factory.newInstance();
// Add new customer
CustomerType customer = doc.addNewCustomers().addNewCustomer();
// set customer info
customer.setId(3);
customer.setFirstname("Jessica");
customer.setLastname("Lim");
customer.setGender("female");
customer.setPhoneNumber("1234567");
// Add new address
AddressType address = customer.addNewAddress();
// Add new PrimaryAddress
PrimaryAddressType primaryAddress = address.addNewPrimaryAddress();
primaryAddress.setPostalCode("350106");
primaryAddress.setAddressLine1("#25-1");
primaryAddress.setAddressLine2("SHINSAYAMA 2-CHOME");
BillingAddressType billingAddress = address.addNewBillingAddress();
billingAddress.setReceiver("Ms Danielle");
billingAddress.setPostalCode("350107");
billingAddress.setAddressLine1("#167");
billingAddress.setAddressLine2("NORTH TOWER HARBOUR CITY");
doc.save(xmlFile);
} catch (Exception ex) {
ex.printStackTrace();
}
String filename = "F://JavaTest//Eclipse//XMLBean//xml//customers_new.xml";
CustomerXMLBean customerXMLBean = new CustomerXMLBean(filename);
customerXMLBean.createCustomer();
}
<Customers>
<customer>
<id>3</id>
<gender>female</gender>
<firstname>Jessica</firstname>
<lastname>Lim</lastname>
<phoneNumber>1234567</phoneNumber>
<address>
<primaryAddress>
<postalCode>350106</postalCode>
<addressLine1>#25-1</addressLine1>
<addressLine2>SHINSAYAMA 2-CHOME</addressLine2>
</primaryAddress>
<billingAddress>
<receiver>Ms Danielle</receiver>
<postalCode>350107</postalCode>
<addressLine1>#167</addressLine1>
<addressLine2>NORTH TOWER HARBOUR CITY</addressLine2>
</billingAddress>
</address>
</customer>
</Customers>
try {
File xmlFile = new File(filename);
CustomersDocument doc = CustomersDocument.Factory.parse(xmlFile);
CustomerType[] customers = doc.getCustomers().getCustomerArray();
for (int i = 0; i < customers.length; i++) {
CustomerType customer = customers[i];
if(customer.getId()==id){
customer.setLastname(lastname);
break;
}
}
doc.save(xmlFile);
} catch (Exception ex) {
ex.printStackTrace();
}
}
String filename = "F://JavaTest//Eclipse//XMLBean//xml//customers_new.xml";
CustomerXMLBean customerXMLBean = new CustomerXMLBean(filename);
customerXMLBean.updateCustomer(3,"last");
}
try {
File xmlFile = new File(filename);
CustomersDocument doc = CustomersDocument.Factory.parse(xmlFile);
CustomerType[] customers = doc.getCustomers().getCustomerArray();
CustomerType customer = customers[i];
if(customer.getId()==id){
customer.setNil() ;
break;
}
}
doc.save(xmlFile);
} catch (Exception ex) {
ex.printStackTrace();
}
}
String filename = "F://JavaTest//Eclipse//XMLBean//xml//customers_new.xml";
CustomerXMLBean customerXMLBean = new CustomerXMLBean(filename);
customerXMLBean.deleteCustomer(3);
}
]]>
q篇是自己关于注解的理解W记
先从RetentionPolicyq个开始把QRetentionPolicy是一个枚举,他是对于~译器的一个声明?br />然而Annotations在编译的q程会中记录到类文g?br />RetentionPolicy的枚举成员一共有三个
SOURCE ~译器要丢弃的注释?br />CLASS ~译器将把注释记录在cL件中Q但在运行时 VM 不需要保留注释?br />RUNTIME ~译器将把注释记录在cL件中Q在q行?VM 保留注释,因此可以反射性地d?Ȁ发注解在q行时生?
Q-Q-在这里注意一下java.lang.reflect.AnnotatedElementq个接口主要定义了获得注解和判断注解是否描述了某个java元素?/font>
在说一下这两个
RetentionQTarget Qjdk提供的注解)
CZ
Target 源码Q?br />@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
说明Q?br /> 1.自己可以描述自己QElementType 描述声明cdQ该注解可以用于哪些元素上边Q?br /> 2.q个注解是用来描q自己定义的元数据,也应该叫做元注解Q然而我们定义的元数据通常是ؓcL者方法而声明的?br />
3.@Retention(RetentionPolicy.RUNTIME
)用来保证在javaq行时运行注解?/font>
其实注解是变向的简化java的反以及把spring{容器ioc和aop的相x念从往常的xml作ؓ元数据提了一个高度声明至cMQ摒弃掉了项?/font>
扩大时冗长的xml的配|?br />
一般通过cL者方法的反射调用注解的方式如?br /> for (Method m : Class.forName(className).getMethods()) {
if (m.isAnnotationPresent(MyAnnotation.class)) {
try {
m.invoke(null);//ҎҎ有无参数讄是否为null
} catch (Throwable ex) {
System.out.printf("p|");
}
}
概念上应注意的几点:
1.在Annotation中,没有默认值的成员必须有一个成员倹{而如何理解默认值是如何被处理就是一个很重要的细节:annotationcd所定义?/font>
成员默认D存储在class文g中,不被~译到annotation里面。如果我们修改一个annotationcd使其成员的默认值发生了改变Q这个改变对
于所有此cd的annotation中没有明提供成员值的成员产生影响Q即修改了该成员的成员|。即使在annotationcd使其成员的默认D
改变后annotation从没被重新编译过Q该cd的annotation(改变前已l被~译?也受到媄响?br />
q篇基本先写到这里,java元数据其实是很大的一块,我只是粗略的看了一下基本的概念Q用来学习ejb作一个铺垫。关于annotation的详情介
l可以阅d考文献中的两文章。在下一章中我要介绍一下ejb中常用的annotation?/font>
参考文献:
jdk源码
Java Annotation入门
http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html
Java Annotation手册
http://www.matrix.org.cn/resource/article/44/44055_Java+Annotation+Reflect.html
在用Hibernate的应用中, Spring的对DAO对象通常的事务管理特别应该引起关注。它的目的就是分L据访问和事务处理Q事务性业务对象不与Q何特D的数据讉K或者事务策略绑在一P从而不影响业务对象的可复用性。这U划分既可以l由事务模板QTransactionTemplateQ用~程的方式实玎ͼ也可以经由面向方面(AOPQ事务拦截器QTransactionTemplateQ用声明的方式实现。无论是本地的Hibernate / JDBC事务Q还是JTA事务都支持对象外的事务策略,q对于本地的无状态会话BeanQStateless Session BeansQ是一个非常有用的选择?/font>
Spring的HibernateTemplatecL供了一个简单的方式实现了Hibernate-based DAO对象而不必关心如何获得Hibernate的Session实例Q也不必兛_多方参与的事务处理。无需使用try-catch块,也无需q行事务查。一个简单的Hibernate讉KҎ完全解决了些麻? 无论是在多个DAO接口q是在多方事务的情况下,Spring使得多种DAO对象无缝地协同工作。例如:某些DAO对象可能是基于plain JDBC的实玎ͼ更适合于经由Spring的JdbcTemplate来避免手动的异常处理?/font>
你可以单独地使用许多SpringҎ,因ؓSpring的所有对象都是设计成可复用的JavaBean对象的集合。也不要因ؓSpring可以提供一个完整的应该框架而气馁!使用其他的SpringҎ时Q应用配|概忉|一个附加的Ҏ,q不是一个必ȝҎ。无论如何,当你要决定去构徏一个象Springq样的内在的基础架构的时候,在用Spring的\途上没有什么范围上的限制?/font>
1. 介绍: 资源理
典型的业务应用系l常常由于重复的资源理代码而导致乱。许多项目试着用自qҎ来解册个问题,有时要ؓ此付出失败的代hQSpring针对适当的资源管理提倡了一U引人注目的单方法:即经由模板来倒置控制QInversion of controlQ,例如Q基cM用回调接口,或者应用AOP拦截器。其基础核心是适当的资源处理和特D的API异常转换Z个unchecked的基异常?/font>
Spring引入了一个DAO异常层适用于Q何数据访问策略。对于直接的JDBCQJdbcTemplatecd注于q接处理Qƈ且关注于对SQLException转换为适当的DataAccessExceptionQ包括对Ҏ的数据库SQL错误转换为有意义的异常?l由不同的事务管理对象,Spring支持JTA和JDBC事务。Spring 也提供对Hibernate和JDO的支持,它的q种支持׃JdbcTemplatecȝ作用相类似的HibernateTemplatecdJdoTemplatec? 以及HibernateInterceptorcRJdoInterceptorc,q有Hibernate、JDO 事务理cȝ成?/font>
最主要的目的是要应用的层ơ分明,为此数据访问和事务处理同应用对象分d来。所有的业务对象都不再依赖数据访问或者事务策略。不再有编码的资源查找代码Q不再有难以替换的单例对象,也不再需要定制服务注册?/font>
所有的单独的数据访问特性均无需依赖于SpringQ可以单独用,无需让Spring知道Q同时也可以通过Spring的应用配|(提供ZXML的配|和Ҏ通JavaBean实例的交叉引用)来进行装配。在一个典型的Spring应用中,大部分重要的对象都是普通的JavaBeanQ数据访问模板对象(data access templatesQ、数据访问对象(使用数据讉K模板对象的对象)、事务管理对象及业务对象Q用数据访问对象和事务对象的对象)Qweb表示分解对象、web控制对象Q用业务对象的对象Q等{?/font>
2. 应用配置中的资源定义
Z避免应用对象资源查扄代码编码,Spring允许在应用配|中一个如JDBC DataSource或者Hibernate SessionFactory定义Z个Bean。应用对象如果需要访问资源只需要通过Bean引用QDAO定义在下一部分说明Q接受先前定义的实例的引用。以下的内容引用自一个应用配|定义,昄了如何徏立一个JDBC DataSource和一个Hibernate的SessionFactoryQ?/font>
<beans>
.JndiObjectFactoryBean">
.LocalSessionFactoryBean">
.MySQLDialect</prop> |
注意选择是用JNDI来定位数据源q是从一个象Jakarta Commons DBCP BasicDataSourceq样的本地定义取得一个数据源Q只是一个改变配|的事:
<bean id="myDataSource"
.dbcp.BasicDataSource" destroy-method="close"> |
你也可以使用一个JNDI查找SessionFactoryQ但是通常对于EJB环境之外的应用来说ƈ不是需要的Q参?container resources vs local resources"部分的讨论)?/font>
3. 倒置控制QInversion of ControlQ? 模板和回?/font>
模板的基本编E模式就象你在下面看到那样Q至于方法就如同M定制的数据访问对象或者业务的对象的方法一栗除了需要向其提供一个Hibernate的SessionFactory之外Q再没有对周围执行对象的信赖的限制。虽然最好是从一个Spring的应用配|中l由一个简单setSessionFactory bean的属性设|用Bean引用来获得它Q但随后你可以从M地方获得它。随后的引用片段包括一D在Spring应用配置中对DAO定义的配|,其中引用了在其前面定义的SessionFactoryQ和一DDAOҎ的实现的例子?/font>
<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> ... </beans> |
public class ProductDaoImpl implements ProductDao { private SessionFactory sessionFactory; public void setSessionFactory(SessionFactorysessionFactory) { this.sessionFactory = sessionFactory; } public List loadProductsByCategory(final Stringcategory) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory); return (List) hibernateTemplate.execute( new HibernateCallback() { public Object doInHibernate(Session session) throwsHibernateException { List result = session.find( "from test.Product product where product.category=?", category, Hibernate.STRING); // do some further stuff with the result list return result; } } ); } } |
一个回调的实现可以被有效地用在MHibernate数据讉K中。在M情况下都由HibernateTemplate来管理Session的开闭和自动的多方事务。模板实例是U程安全和可重用的,因此它们可以做ؓ其他cȝ变量?/font>
对于单的单步的动作,象find, load, saveOrUpdate或者delete的调用,HibernateTemplate提供更ؓ便利的选择以代替象一行的回调的执行。此外,Spring提供了一个方便的基本c,是HibernateDaoSupportc,它提供了setSessionFactoryҎ来接受一个SessionFactoryQ同时提供了getSessionFactory和getHibernateTemplateҎ供其l承cM用。将q些l合hQ允许对于典型的需求给Z非常单的DAO实现Q?/font>
public class ProductDaoImpl extends HibernateDaoSupport implementsProductDao { public List loadProductsByCategory(String category) { return getHibernateTemplate().find( "from test.Product product where product.category=?", category, Hibernate.STRING); } } |
4. 应用一个AOP拦截器代替一个模?/font>
除用HibernateTemplate之外的另一个选择是使用Spring的AOP HibernateInterceptor。用直接在一个委托的try/catch块中~写Hibernate代码Q配合相应的在应用配|中分别的拦截器配置来代替执行回调。下面的片段昄了一个Spring应用配置中的DAO, interceptor和proxy的各自的定义Q同时给Z一个DAOҎ实现的例子:
<beans> ... <bean id="myHibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductDaoTarget" class="product.ProductDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductDao" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>product.ProductDao</value> </property> <property name="interceptorNames"> <list> <value>myHibernateInterceptor</value> <value>myProductDaoTarget</value> </list> </property> </bean> ... </beans> |
public class ProductDaoImpl extends HibernateDaoSupportimplements ProductDao { public List loadProductsByCategory(final String category)throws MyException { Session session = SessionFactoryUtils.getSession(getSessionFactory(), false); try { List result = session.find( "from test.Product product where product.category=?", category, Hibernate.STRING); if (result == null) { throw new MyException("invalid search result"); } return result; } catch (HibernateException ex) { throw SessionFactoryUtils.convertHibernateAccessException(ex); } } } |
q个Ҏ只在有一个与它配合的HibernateInterceptor时才能正常工作,HibernateInterceptor为它负责在方法调用前U程l定Session的开启和Ҏ调用后的关闭。getSessionҎ调用中的"false"标志是要认Session必须是已l存在的Q如果没有发CQ何一个SessionQSessionFactoryUtils会为其创徏一个。如果已l有一个Session句柄l定在本U程上,比如是由一个HibernateTransactionManager事务l定的,在Q何情况下SessionFactoryUtils会自动接入这个Session。HibernateTemplate在底层也使用SessionFactoryUtilsQ与以上说的方式基本是一L?/font>
HibernateInterceptor的主要益处是它允许在数据讉K代码中抛出checked application exceptionQ而HibernateTemplate׃受限于回调只能在其中抛出unchecked exceptions。注意到q点我们可以推迟各自的检验,同时在回调后抛出应用异常。拦截方式的主要~点是它需要在配置中进行特D的配置。HibernateTemplate在大多数情况下都是一U简单好用的Ҏ?br />
5. E序事务划分
在这U底层的数据讉K服务之上Q事务处理可以在更高的应用层被划?QŞ成一些操作。这里除了需要一个Spring的PlatformTransactionManager对象外,对于周围q行的业务对象也没有M限制。同LQ其后你可以从Q何地方获得它们,但是l由Bean引用的方式通过setTransactionManageҎ获得更ؓ适合Q象productDAO要经׃个setProductDaoҎ获得一栗下面的引用片段昄了在一个Spring应用配置中的事务理对象和业务对象的定义Qƈ且还提供了一个业务方法实现的例子Q?/font>
<beans> ... <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductService" class="product.ProductServiceImpl"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="productDao"> <ref bean="myProductDao"/> </property> </bean> </beans> |
public class ProductServiceImpl implements ProductService { private PlatformTransactionManager transactionManager; private ProductDao productDao; public void setTransactionManager(PlatformTransactionManagertransactionManager) { this.transactionManager = transactionManager; } public void setProductDao(ProductDao productDao) { this.productDao = productDao; } public void increasePriceOfAllProductsInCategory(final Stringcategory) { TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager); transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); transactionTemplate.execute( new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult(TransactionStatusstatus) { List productsToChange = productDAO.loadProductsByCategory(category); ... } } ); } } |
6. 声明性事务划?/font>
我们q可以选择使用Spring的AOP TransactionInterceptor通过在应用配|中定义拦截器配|来代替事务划分代码的事务处理方式。这允许我们保持业务对象独立于每个业务对象中重复的事务划分代码。此外,事务行ؓ和隔dơ的变化可以通过一个配|文件来改变而不需要对业务对象的实现造成影响?/font>
<beans> ... <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myTransactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="transactionAttributeSource"> <value> product.ProductService.increasePrice*=PROPAGATION_REQUIRED product.ProductService.someOtherBusinessMethod=PROPAGATION_MANDATORY </value> </property> </bean> <bean id="myProductServiceTarget" class="product.ProductServiceImpl"> <property name="productDao"> <ref bean="myProductDao"/> </property> </bean> <bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>product.ProductService</value> </property> <property name="interceptorNames"> <list> <value>myTransactionInterceptor</value> <value>myProductServiceTarget</value> </list> </property> </bean> </beans> |
public class ProductServiceImpl implements ProductService { private ProductDao productDao; public void setProductDao(ProductDao productDao) { this.productDao = productDao; } public void increasePriceOfAllProductsInCategory(final Stringcategory) { List productsToChange = this.productDAO.loadProductsByCategory(category); ... } } |
如同使用HibernateInterceptor一PTransactionInterceptor允许Mchecked application exception从回调代码中抛出Q而TransactionTemplate受回调限制在其内部抛出unchecked exceptionsQ在出现一个unchecked application exception的情冉|QTransactionTemplate引发一个回滚或者这个事务由应用Q通过事务状态)标记为回滚。TransactionInterceptor默认情况也是同样的行为,但是允许为每一个方法制定回滚策略?br /> 建立声明性事务的一个便利的方式是用TransactionProxyFactoryBeanQ特别是如果没有其他AOP拦截器的话,TransactionProxyFactoryBean联合定义ؓ代理的自w与一个特D的目标Bean的事务配|。这减一个代理Bean对应一个目标Bean的配|情c此外,你不必指定哪个接口或者哪个类必须定义事务Ҏ?/font>
<beans> ... <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductServiceTarget" class="product.ProductServiceImpl"> <property name="productDao"> <ref bean="myProductDao"/> </property> </bean> <bean id="myProductService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="target"> <ref bean="myProductServiceTarget"/> </property> <property name="transactionAttributes"> <props> <prop key="increasePrice*">PROPAGATION_REQUIRED</prop> <prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop> </props> </property> </bean> </beans> |
7. 事务理{略
对于Hibernate应用来说Q无论是TransactionTemplateq是TransactionInterceptor都是委托验实际的事务处理lPlatformTransactionManager实例Q可以是一个HibernateTransactionManagerQ由一个单一的Hibernate的SessionFactoryQ用一个ThreadLocal SessionQ或者可以是一个JtaTransactionManagerQ代理容器的JTA子系l)。甚至你可以使用一个自定义的PlatformTransactionManager实现?br /> 如果选择从本地Hibernate事务理转ؓ由JTA来进行事务管理,例如Q当你的应用的部|面对分布的事务需求时Q也仅仅是改变一下配|的事。只要简单地Hibernate的事务管理换为JTA事务实现卛_。所有的事务划分和数据访问无需做Q何变动仍可以l箋工作Q因Z们用的都是普通的事务理API?br /> 对于分布式的事务会跨多个Hibernate的session factoriesQ仅仅是联合JtaTransactionManager与多个LocalSessionFactoryBean定义作ؓ事务{略。你的每一个DAO通过它们各自的Bean属性得C个特D的SessionFactory的引用。如果这一切都是在下面的JDBC数据源是事务容器Q一个业务对象可以划分事务跨很多DAO和很多session factories而无需做特别的处理Q对于用JtaTransactionManager做ؓ事务{略也是一L?/font>
<beans> <bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>jdbc/myds1</value> </property> </bean> <bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>jdbc/myds2</value> </property> </bean> <bean id="mySessionFactory1" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="mappingResources"> <list> <value>product.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop> </props> </property> <property name="dataSource"> <ref bean="myDataSource1"/> </property> </bean> <bean id="mySessionFactory2" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="mappingResources"> <list> <value>inventory.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop> </props> </property> <property name="dataSource"> <ref bean="myDataSource2"/> </property> </bean> <bean id="myTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory1"/> </property> </bean> <bean id="myInventoryDao" class="product.InventoryDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory2"/> </property> </bean> <bean id="myProductServiceTarget" class="product.ProductServiceImpl"> <property name="productDao"> <ref bean="myProductDao"/> </property> <property name="inventoryDao"> <ref bean="myInventoryDao"/> </property> </bean> <bean id="myProductService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="target"> <ref bean="myProductServiceTarget"/> </property> <property name="transactionAttributes"> <props> <prop key="increasePrice*">PROPAGATION_REQUIRED</prop> <prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop> </props> </property> </bean> </beans> |
无论是HibernateTransactionManagerq是JtaTransactionManager允许适当的对Hibernate的在JVM层次的缓存处?不需要容?提供Ҏ的事务查找或者JCAq接器(只要不用EJB发v事务Q。另外,HibernateTransactionManager能输出JDBCq接供通常的JDBC讉K代码使用。这样就允许在高层次上的事务划分是合了Hibernate与JDBC而不要JTA的,只要只是讉K一个数据库可以!
8. 使用Spring理应用的Bean
一个Spring应用配置定义可以被多U配|实现所加蝲Q从FileSystemXmlApplicationContext和ClassPathXmlApplicationContext到XmlWebApplicationContext。这允许在各种环境下重用Spring理的数据访问和业务对象。默认情况下Q一个Web应用有它自q定义在“WEB-INF/applicationContext.xml”中的根配置?br /> 在Q何一个Spring应用中,一个应用配|定义在一个XML格式的文件中用来对应用的所有有关的Beanq行装配Q从Hibernate的session factory到自定义的数据访问和业务对象Q象上面所有的Bean那样Q。他们中的大多数不需要Spring容器知道他们Q甚臛_使是与其他Bean合作时也一P因ؓ他们只是单的JavaBean之间的协作。下面的Bean定义可能是一个Spring Web 的MVC配置中用来访问业务对象的配置的一部分?/font>
<bean id="myProductList" class="product.ProductListController"> <property name="productService"> <ref bean="myProductService"/> </property> </bean> |
Spring的Web控制器经由Bean引用拥有它们需要的所有的业务和数据访问对象,因此它们无需在应用配|中做Q何手工的Bean查找。但是当使用Spring理的Beans用于Struts或者是在EJB实现Q或者一个applet中时常常是需要必L工查找一个Bean的。因此Spring的Bean可以被用在Q何地斏V也许只是需要是一应用配置的引用,或者经׃个web容器的Servlet配置属性,或者从一个文件中或者类路径的资源中创徏它?/font>
ApplicationContext context =WebApplicationContextUtils.getWebApplicationContext(servletContext); ProductService productService = (ProductService) context.getBean("myProductService"); |
ApplicationContext context = new FileSystemXmlApplicationContext("C:/myContext.xml"); ProductService productService = (ProductService) context.getBean("myProductService"); |
ApplicationContext context = new ClassPathXmlApplicationContext("myContext.xml"); ProductService productService = (ProductService) context.getBean("myProductService"); |
9. 容器资源VS本地资源
Spring的资源管理允许简单地在一个JNDI SessionFactory和一个本地SessionFactory间做选择Q同样允许在一个JNDI DataSource与本地DataSource间做选择Q而无需改变应用的一行代码。在容器中保存资源定义还是在应用本地保存Q主要是一个事务策略方面的事。比较一个Spring定义的本地SessionFactory与一个手工注册的JNDI SessionFactory没有M益处。如果经由Hibernate的JCAq接器注册,才会有加入JTA事务的明昄处,特别是对EJB?/font>
一个重要的Spring事务提供的好处是它不与Q何容器绑定。定义包括JTA在内的策略,它都可以独立工作或者在一个试验环境中工作。特别是对典型的一个数据库的事务来_对于JTAq是一个非常轻量的和强大的选择。当使用本地EJB SLSB的事务时Q你同时依赖EJB容器和JTA-即你只是访问一个数据库Q即使只是用SLSBsl由CMT来声明事务。选择使用 JTA~程也需要一个J2EE环境?/font>
JTA自n和JNDI数据源来说JTA不只是包括容器依赖。对于不使用Spring的JTA驱动的Hibernate事务Q你必须使用HibernateJCAq接器或者在合适的JVM~冲层专门写Hibernate的事务代码配|JTA事务。在只访问一个数据库的情况下QSpring驱动的事务可以与一个本地定义的Hibernate的SessionFactory配合良好Q就如同与一个本地JDBC数据源相配合一栗因此当面对分布的事务需求时Q你只需要{换ؓSpring的JTA事务{略卛_?
要注意一个JCAq接器需要特别的容器的部|步骤,q且昄首先得支持JCA。这比用本地资源定义和Spring驱动事务来部|一个简单的Web应用有更多的争议。而且你常帔R要企业版本的容器支持Q象WebLogic Express׃提供JCA。一个只用一个数据库的用本地资源和事务的Spring应用可以在Q何J2EE的Web容器中工作,Web容器不必支持JTA, JCA和EJBQ如QTomcat, Resin甚至最的Jetty。另外,q样一个中间层可以很Ҏ地在桌面应用或者在试套g中被重用?/font>
所有考虑q的事情包括Q如果你不用EJBQ坚持用本地SessionFactoryQ用SpringHibernateTransactionManager或者JtaTransactionManagerQ你获得包括适当处理的JVM层的~存和分布事务的所有益处,而无需引vM关于容器部v的争论。经由JCAq接器的一个Hibernate的SessionFactory的JNDI注册只是在用EJB的情况中才会有明昄附加倹{?/font>
10. Skeletons和例?/font>
配置使用Spring和HIbernate的一个J2EE的Web应用的注释和l节最好去看看在Spring Framework的例子中的“典型的Web应用”SkeletonsQ它l出了适合于JDBC ?Hibernate应用的多U数据源及事务管理的配置,仔细看一下事务拦截器的配|,它也同样向你展示了如何配|AOP拦截器?/font>
在Spring?.0 M2版中Q例子Petclinic提供了JDBC和Hibernate的DAO实现和应用配|的选择。Petclinic
可以作ؓ一个可工作的简单应用说明如何在一个Spring web 应用中用HibernateQ同样也包括Ҏ不同的事务策略来声明事务划分?br />
Spring Framework documentation
我们使用Sub VersionQ简U?/span>SVNQ作为版本管理工兗这里着重介l?/span>SVN作ؓ跨^台的多h协作使用Ҏ。在多个E序员管理同一D代码的q程中,版本的管理显得尤为重要,使用SVN可以方便的进行分支、合qӞ记录下所有的版本?/span>
基本配置在开始某Y件、文档的开发与撰写Ӟ首先由配|管理负责h建立SVN仓库、用户名及其权限Qƈ通知相关人员SVN仓库地址?/span>SVN仓库负责人?/span>
SVN仓库的负责h把工E的tsvn:logminisize讄?/span>1Q以便强制注释。设|方法:在你的工E文件夹右键->属性中Q进?/span>Subversion标签Q选中tsvn: logminisizeQ确保复选框recursive选中Q然后点?/span>Set按钮把它的D?/span>1Q其意思是指提交的注释最短长度ؓ一个字。如图:
?/span> 2 . 1
软g配置l 忽略文g
?/span>
SVN
?/span>
[Setting]
?/span>
[General]
?/span>
Q?/span>
讄需要忽略的文g以便忽略掉一些时的、无用的文g
Q?/span>
常被忽略的文件有
*.opt *.ncb *.suo *.plg *.pch *.idb *.pdb *.scc *.obj Debug Release *.o *.bin *.out *.ilk *.aps debug release *.clw *.bak
。每个程序员可以Ҏ自己的需要进行修改忽略文Ӟ上面只是使用VC++?/span>Tornado~程时常用的一些忽略文件?/span>
?/span> 2 . 2
以上说的忽略文g是指全局的忽略文件?/span>SVNq能在特定的目录中指定需要忽略的文g。忽略文件支持通配W?/span>
l 合ƈ比较工具
?/span>Merge Tool中可以选择用来合ƈ的工P强烈推荐?/span>Araxis Merge。在[Setting]->[Diff]中填?/span>"C:\Program Files\Araxis\Araxis Merge v6.5\Merge.exe"Q在[Setting]->[Merge]的选项中,填入"C:\Program Files\Araxis\Araxis Merge v6.5\Merge.exe" %theirs %mine %merged Q其?/span>"C:\Program Files\Araxis\Araxis Merge v6.5\Merge.exe"是指合ƈ工具的\径,%theirs %mine %merged分别?/span>..要合ƈCq的分支Q主qԌ及合q后的结果?/span>
?/span> 2 . 3
仓库目录l构SVN仓库的负责h规划好仓库的目录l构。推荐的目录l构如下图所C?/span>
仓库的一U目录只有两个,分别?/span>code?/span>doc。其中,doc主要用来攄先期的文档,code主要用来攄工程的代码,也可以包含后期的文档?/span>
仓库的二U目录只可以?/span>branch?/span>trunk两个目录Q分别存放主q与分支?/span>trunk目录下直接存攑ַE文件?/span>branch目录下包括一些子目录分别对应各个分支?/span>
?/span> 2 . 4
?/span> SVN 仓库中取Z码时 Q一?/span> 不要把整个仓库取出来 Q?/span> 而应该只取出 trunk 目录 Q?/span> 或只取出 branch 下的某个分支目录 Q比 如上图中?/span> svn:\\code\branch\xw_051206 Q?/span> ?/span>
一个项目会有多个h共同合作开发完成。基本流E是Q?/span>
l 各开发成员徏立自q分支Qƈ在此分支上开发;
l 各开发成员把分支合ƈCq上qŞ成较为稳定的版本Q?/span>
l 各个成员重新从主q上建立新的分支Q在此分支上开?/span> ( 卛_到第一?/span> )
l 循环往复,直到工程l束?/span>
下面我用一个例子来说明合作开发的基本程?/span>
现在xb?/span>lzj两个开发h员要共同开发一个工E?/span>onlytestQ其q个工程的主q的SVN仓库地址如下图?/span>
?/span> 2 . 5
xb?/span>lzj分别?/span>onlytestq个工程中徏立两个分支,分别?/span>xb _051115?/span>lz_051115?/span>
在这里分支命名要采用[姓名~写_6个数的日?/span>_后缀(可?/span>)]的Ş式,比如xb_051208_1Q?/span>xb_051212之类的。创建完分支后我们可以看到这个工E的目录l构如下图所C:
?/span> 2 . 6 分支目录
建完之后Q?/span> xb?/span>lzj分别在本地取出对应的分支q行开发?/span>
?/span> E序到达一个比较稳定的阶段Q就需要把分支合ƈCq上Q下面讲qC下合q的程?/span>
在本节中l箋使用上一节中所C的工程?/span>SVN仓库讲解?/span>
1.2.3.1 xb ?/span> lzj 分别修改自己分支上的代码现在 Q?/span> d上的 test_SVN.txt 是空文档?/span>
?/span> xb ?/span> lzj 修改提交?/span> Q?/span> 两个分支?/span> test_SVN.txt 分别如下两图所C?/span> Q?/span>
?/span> 2 . 7 xb_051129 分支下的 test_SVN.txt
?/span> 2 . 8 lzj_051129 分支下的 test_SVN.txt
1.2.3.2 xb ?/span> xb_051129 分支合ƈCq?/span>xb 先把d check out 到本地。然后在d的目录上右键 选择svn->mergeQ弹出如下窗口:
?/span> 2 . 9 合ƈ对话?/span>
此对话框的含义是?/span>From指定的分支版本到To指定的分支版本之间的差异合ƈCq上?/span>
在这里分支选的?/span>xb_051129。版本号的选定Ҏ是点?/span>From中的Show LogQ在LogH口中按?/span>Ctrl键,点击选择”made a copy?span style="font-family: 宋体;">之上的那个版本,以及最上的那个版本,?/span>?/span>2.11所C。然后点ȝ定回C图中的对话框Q会自动填写From?/span>To中的Revision受?/span>
然后直接点击mergeq行合ƈQ你也可以通过dry run来看是不是两者之间有差异。由于没有其它h修改dQ所以合q的很顺利,下图?/span>xb_051115与主q合q后的结果。合q完毕之后,?/span>xb对主q进行提交?/span>
?/span> 2 . 11 合ƈ后,d上的 test_SVN.txt
1.2.3.3 lzj ?/span> lzj_051129 分支合ƈCqԌ解决冲突
xb合ƈ完毕之后Q?/span>lzj要将他的分支合ƈCq上去,Ҏ同上。但是由?/span>xb已经修改q主qԌ所以生了冲突Q会弹出一个冲H对话框。双d话框中的产生冲突的文件名Q就可以调出工具Ҏ文gq行合ƈQ下图是我们?/span>merge工具昄的界面?/span>
?/span> 2 . 12
l 首先比较W一个窗口与W二个窗口,把结果修改合q到W二个窗口?/span>
l 然后保光标处于W二个窗口时Q点M图中U色圈圈所C的按钮。这样会把第二个H口的内容全部复制到W三个容口。之后保存,退出?/span>
l 然后在工E目录上点右键,q行SVN->Resolved。这样会删除无用的时文件?/span>
l 最后提交所作的修改Qƈd详细的注释?/span>
中的标签?/span>CVS不同Q?/span>SVN时不用专门ؓ目录d标签Q因?/span>SVN也对目录q行版本理?/span>
我们在提交时写好注释Q比如重要的版本提交时?/span> 051201 之类的日期作为开_Q就可以通过注释来查找比较重要的目录版本P相当?/span> CVS ?/span> VSS 中的标签?/span>
另外Q每个工E都会有一个版本说明文Ӟ通过此文件可以查扑օ键版本?/span>
你可以重命名、移动或删除你的文g或文件夹Q但请?/span>SVNq行q些操作Q否则之前的版本信息会丢失?/span>
使用SVN删除、移动与重命名文件夹的方法是在文?/span>/文g夹上点右键进?/span>SVN操作Q或直接在资源浏览器中用右键拖放(会弹?/span>SVN选项Q?/span>
文g的删除、移动与重命名之前,必须保证工作目录是最新的版本Q进行这些操作之后,需要进行提交?/span>
1.3.3 版本的回退在代码的~写q程中,隑օ会有不尽人意的地方,你也讔R要回退到某一个版本,但是在这个过E中可能有一些文件你想保留,也有一些文件你不想保留Q这q扯到很复杂的版本理q程Q在q里l大家推荐几U方法?/span>
1. 若是你编辑了工程Q在没有提交的前提下Q你x弃这些修改,你可以直接选择 revert 可以更新到工程的最新的版本?/span>
2. 若是你想退回到某一个版本,你就可以直接选择 update to reversion 如图 , q样我们可以把我们的版本回退C选中的版本去Q这U情况下 SVN q没有显C出有什么冲H,q且新徏立的文g也还在,但是在这U情况下你ƈ不能直接在你回退后的版本上进行编辑,因ؓ SVN 的版本控制还是在最新的d上。我们需?/span> update q解军_H?/span>
3. 你可以直接选择 revert changes from this revision 如图Q这L话你可以直接解决冲突q提交。不q这U方法的不是,你新建的文g都没有了Q整个工E都回退C前的版本了?/span>
4. 我推荐的一U方法是Q直?/span> export 一个你需要的版本Q然后用?/span> export 的版本覆盖你的最新的版本Q这样你可以不丢失你新建的文gQ同时获?/span> head ?/span> SVN 控制文g?/span>
?/span> 13
每个工程会有很多个小模块Q当某个模块辑ֈE_的时候,你就需要提交一ơ,以免写下个模块代码的时候出C可恢复的错误?/span>
每一ơ提交需要前Q需要通过pclint查,保证是一个编译没有错误的版本。当提交比较E_的版本的时候,同时要修改你的版本号?/span>
1.3.5 版本说明文g版本说明文g?/span>xml表格Q可?/span>excel~辑Q它会记录下关键的版本信息?/span>
版本说明文g内容如下表。发布版本是指用户对外公布的版本P后文中有详细描述Q?/span>Revision?/span>SVN内部的工E文件夹的版本号。一个发布版本可能对应多?/span>RevisionQ?/span>
发布版本 |
Revision |
详细说明 |
1,0,0,12 |
76 |
加入了抗q扰日志Q需长时间测?/span> E序代码q行了重构,已经调试通过 |
77 |
xxx @#$%^& |
|
78 |
?/span>... |
|
1,0,0,13 |
81 |
试q的E_版本 |
1,0,0,14 |
99 |
fix some bugQ没有测?/span> |
|
|
|
附g | 大小 |
---|---|
svn版本理教程.rar | 474.51 KB |
快门和光圈优先:
Z得到正确的曝光量Q就需要正的快门与光圈的l合。快门快Ӟ光圈p大些Q快门慢Ӟ光圈p些。快门优先是指由机器自动光pȝ计算出暴光量? |然后Ҏ你选定的快门速度自动军_用多大的光圈。光圈优先是指由机器自动光pȝ计算出暴光量的|然后Ҏ你选定的光圈大自动决定用多少的快门? 拍摄的时候,用户应该l合实际环境把曝光与快门两者调节^衡,相得益嘪?/font>
光圈大Q则单位旉内通过的光U越多,反之则越。光圈的一般表C方法ؓ字母“F+数值”,例如F5.6、F4{等。这里需要注意的是数D,表示? 圈越大,比如F4p比F5.6的光圈大Qƈ且两个相ȝ光圈g间相差两倍,也就是说F4比F5.6所通过的光U要大两倍。相Ҏ说快门的定义很? 了,也就是允许光通过光圈的时_表示的方式就是数|例如1/30U?/60U等Q同样两个相d门之间也相差两?/font>
光圈和快门的l合Ş成了曝光量,在曝光量一定的情况下,q个l合不是惟一的。例如当前测出正常的曝光l合为F5.6?/30U,如果光圈增大一U也 是F4Q那么此时的快门值将变ؓ1/60Q这Ll合同样也能辑ֈ正常的曝光量。不同的l合虽然可以辑ֈ相同的曝光量Q但是所拍摄出来的图片效果是不相 同的?/font>
快门优先是在手动定义快门的情况下通过相机光而获取光圈倹{D例说明,快门优先多用于拍摄运动的物体上,特别是在体育q动拍摄中最常用。很多朋友在拍摄 q动物体时发玎ͼ往往拍摄出来的主体是模糊的,q多半就是因为快门的速度不够快。在q种情况下你可以使用快门优先模式Q大概确定一个快门|然后q行? 摄。因为快门快了,q光量可能减,色彩偏EQ这需要增加曝光来加强囄亮度。物体的q行一般都是有规律的,那么快门的数g可以大概估计Q例如拍摄行 人,快门速度只需?/125U就差不多了Q而拍摄下落的水滴则需?/1000U?/font>
手动曝光模式Q?/strong>
手控曝光模式每次拍摄旉需手动完成光圈和快门速度的调节,q样的好处是方便摄媄师在刉不同的囄效果。如需要运动轨q的囄Q可以加长曝光时_把快 门加快,曝光增大Q如需要制造暗淡的效果Q快门要加快Q曝光要减少。虽然这L自主性很高,但是很不方便Q对于抓拍瞬息即逝的景象Q时间更不允许?/font>
AE模式Q?/strong>
AE全称为Auto ExposureQ即自动曝光。模式大U可分ؓ光圈优先AE式,快门速度优先AE式,E式AE式,闪光AE式和深度优先AE式。光圈优先AE式是由拍摄? Zؓ选择拍摄时的光圈大小Q由相机Ҏ景物亮度、CCD感光度以及h为选择的光圈等信息自动选择合适曝光所要求的快门时间的自动曝光模式Q也卛_圈手动? 快门旉自动的曝光方式。这U曝光方式主要用在需优先考虑景深的拍摄场合,如拍摄风景、肖像或微距摄媄{?/font>
多点光Q?/strong>
多点光是通过Ҏ物不同位|的亮度Q通过闪光灯补偿等办法Q达到最佳的摄媄效果Q特别适合拍摄别光物体。首先,用户要对景物背景Q一般ؓ光源物体q行? 光,然后q行AE锁定Q第二步是对背光景物q行光Q大部分的专业或准专业相机都会自动分析,q用闪光灯ؓ背光物体q行补光?/font>