??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
原理Q在Action中取得BeanFactory对象Q然后通过BeanFactory获取业务逻辑对象
1、spring和struts依赖库配|?br /> * 配置struts
--拯strutscd和jstlcd
--修改web.xml文g来配|ActionServlet
--提供struts-config.xml文g
--提供国际化资源文?br /> * 配置spring
--拯springcd
--提供spring配置文g
2、在struts的Action中调用如下代码取得BeanFactory
BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());
3、通过BeanFactory取得业务对象Q调用业务逻辑Ҏ
spring+struts的集?W二U集成方?
原理Q将业务逻辑对象通过spring注入到Action中,从而避免了在ActioncM的直接代码查?/p>
1、spring和struts依赖库配|?br /> * 配置struts
--拯strutscd和jstlcd
--修改web.xml文g来配|ActionServlet
--提供struts-config.xml文g
--提供国际化资源文?br /> * 配置spring
--拯springcd
--提供spring配置文g
2、因为Action需要调用业务逻辑ҎQ所以需要在Action中提供setterҎQ让spring业务逻辑对象注入q来
3、在struts-config.xml文g中配|Action
* <action>标签中的type属性需要修改ؓorg.springframework.web.struts.DelegatingActionProxy
DelegatingActionProxy是一个ActionQ主要作用是取得BeanFactoryQ然后根?lt;action>中的path属性?br /> 到IoC容器中取得本ơ请求对应的Action
4、在spring配置文g中需要定义struts的Action,如:
<bean name="/login" class="com.bjsxt.usermgr.actions.LoginAction" scope="prototype">
<property name="userManager" ref="userManager"/>
</bean>
* 必须使用name属性,name属性值必dstruts-config.xml文g?lt;action>标签的path属性g?br /> * 必须注入业务逻辑对象
* scope讄为prototype,q样避免了struts Action的线E安全问?br />
成SQL语句Q对比其他的数据库持l层和ORM框架Q如JDO的实玎ͼHibernate{)QSQL Map最大的优点?/p>
于它单易学。要使用SQL MapQ只要熟悉Java BeanQXML和SQLQ就能您充分发挥SQL语句的能力?/p>
1. com.ibatis.sqlmap.client.SqlMapClient
一个用SQL Maps(从这个类开始运行的)的,U程安全的客L。这个接口通过l承
SqlMapTransactionManager和SqlMapExecutor接口获得了事务控制和执行Ҏ?br /> SqlMapClient是用SQL Maps 的核心类。这个类允怽映射操作语句(select、insert?/p>
update、delete{?Q而且q划分了事务界线q能使用批处理。一旦你拥有了一个SqlMapClient实例Q你
使用SQL 映射变得_单?br /> SqlMapClient能够直接作ؓ多线E客L使用(内部session理)Q或者你也能得到一个单U程
的sessionq且使用它。如果你明确的获得一个session(使用 openSession()Ҏ)的话Q这里可能有一
点轻微性能的提升,因ؓq样节省了SqlMapClient理U程上下文信息的开销。但是在大多数的情况?/p>
Q这不会产生什么不同,因此你可以选择L一个你需要或喜欢的方式?br /> 一个SqlMapClient实例可以被安全地作ؓ静态的Q或者实Cؓ一个单例。一般来_好的x
是,做成一个简单的配置c,而通过SqlMapClientBuilder去配|这个类的事例?br /> 其实是客户端程序员q行Sql Map操作的客LcR?br />SQL Maps (com.ibatis.sqlmap.*)
SQL Map的概?br />SQL Map API让开发h员可以轻易地Java Bean映射成PreparedStatement的输入参数和ResultSetl果
集。开发SQL Map的想法很单:提供一个简z的架构Q能够用20Q的代码实现80QJDBC的功能?br />SQL Map如何工作Q?
SQL Map提供了一个简z的框架Q用简单的XML描述文gJava BeanQMap实现和基本数据类型的包装
c(StringQInteger{)映射成JDBC的PreparedStatement。以下流E描qCSQL Maps的高层生命周?/p>
Q?
一个对象作为参敎ͼ对象可以是Java BeanQMap实现和基本类型的包装c)Q参数对象将为SQL修改?/p>
句和查询语句讑֮参数倹{?br />1) 执行mapped statement。这是SQL Maps最重要的步骤。SQL Map框架创Z个PreparedStatement?/p>
例,用参数对象ؓPreparedStatement实例讑֮参数Q执行PreparedStatementq从ResultSet中创建结?/p>
对象?br />2) 执行SQL的更新数据语句时Q返回受影响的数据行数。执行查询语句时Q将q回一个结果对象或对象
的集合。和参数对象一Pl果对象可以是Java BeanQMap实现和基本数据类型的包装cR?/p>
下面是用SqlMapClient的示例代码:
//
// autocommit simple query --these are just examples...not patterns
//
Employee emp = (Employee) sqlMap.queryForObject("getEmployee", new Integer(1));
//
// transaction --these are just examples...not patterns
//
try {
sqlMap.startTransaction()
Employee emp2 = new Employee();
// ...set emp2 data
Integer generatedKey = (Integer) sqlMap.insert ("insertEmployee", emp2);
emp2.setFavouriteColour ("green");
sqlMap.update("updateEmployee", emp2);
sqlMap.commitTransaction();
} finally {
sqlMap.endTransaction();
}
//
// session --these are just examples...not patterns
//
try {
SqlMapSession session = sqlMap.openSession()
session.startTransaction()
Employee emp2 = new Employee();
// ...set emp2 data
Integer generatedKey = (Integer) session.insert ("insertEmployee", emp2);
emp2.setFavouriteColour ("green");
session.update("updateEmployee", emp2);
session.commitTransaction();
} finally {
try {
session.endTransaction();
} finally {
session.close();
}
// Generally your session scope would be in a wider context and therefore the
// ugly nested finally block above would not be there. Realize that sessions
// MUST be closed if explicitly opened (via openSession()).
}
//
// batch --these are just examples...not patterns
//
try {
sqlMap.startTransaction()
List list = (Employee) sqlMap.queryForList("getFiredEmployees", null);
sqlMap.startBatch ();
for (int i=0, n=list.size(); i < n; i++) {
sqlMap.delete ("deleteEmployee", list.get(i));
}
sqlMap.executeBatch();
sqlMap.commitTransaction();
} finally {
sqlMap.endTransaction();
}
2、关于hibernate.hbm2ddl.auto
<property name="hibernate.hbm2ddl.auto">update</property>
这个属性设?update 只有我们发生修改的时候才会重新创 否则不会被覆盖掉Q未理解Q?/p>
Q在SessionFactory创徏Ӟ自动查数据库l构Q或者将数据库schema的DDL导出到数据库。?
create-drop?在显式关闭SessionFactoryӞdrop掉数据库schema.
例如Q我们将所有的表都删除了当我们执行插入操作ӞSessionFactory被创建那么会自动
查数据库scheme的DDLQ徏立数据表Qƈ且会保留原来的数据,所以我们不?Export 配置中的数据到数
据库Q那样会覆盖掉所有的数据?/p>
3、 关于对象关pM息导?br />q里必须调用 configure Ҏ 否则会映?properties 文g
Configuration cfg = new Configuration().configure();
//用于导出用户定义?xml 配置信息Q在数据库中生成对应的Table
SchemaExport export = new SchemaExport(cfg);
export.create(true, true);
4? 试lazy在class上的{略 q里默认为true
我们在这里应当搞清session.get()和session.load()的区?br />Ҏload支持 lazyQ在Session~存中生成一个User的子cd象返回,只有当调用方法是才查询) 如果
不存在查询的l果则抛异常
session = HibernateUtil.getSession();
tx = session.beginTransaction();
Classes c1 = (Classes)session.load(Classes.class, 1);
System.out.println("c1.getId()"+c1.getId());
System.out.println("c1.getName()"+c1.getName());
q里不会发出sql语句Q因里就采用lazy{略Q所以这里采用了W三方的lgq回了一?一个新?
Classes 的实例(代理Q,只有当我们需要查询属性时才会发出sql语句,在这里不会发出sql语句因ؓ
id 是我们输入的?br />hibernate 支持的lazy {略只在session的生命周期内有效?/p>
5、lazy在collection上的{略
很显然这些lazy都是默认?br /> Classes c1 = (Classes)session.load(Classes.class, 1);
//如果我们集合上的lazy设ؓfalseQ这里会发出两条sql除了要查询?/p>
普通属性查出来外,q会非普通属?br /> //集合上的lazy设ؓextra和true是一L
System.out.println("c1.name= " + c1.getName());
//没有发出sql 但是会生成一?persistent 的set作ؓ代理
Set students = c1.getStudents();
for(Iterator it = students.iterator();it.hasNext();){
Student s = (Student)it.next();
System.out.println("student.name= " + s.getName());
}
//System.out.println("student.number= " + student.size());
//q里会将所有的数据d出来q生成对象存攑֜set?br /> /*q里Classes的lazy{略只对普通的属性有养I而collection的lazy{略才对
* collection对象生效*/
*试在标{上的lazy {略和集合上的lazy{略一栗?br />6、one2one
<class name="org.n2535.hibernate.Person" table="t_person">
<id name="id">
<!-- q里表示了Person的主键是作ؓ一个外键关联了IdCard的主?-->
<generator class="foreign">
<!-- 表示主键的生成是Ҏ 属?idCard ?id -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name" />
<!-- 表示了Person与Idcard是一对一的关p?默认为根据主键加载对象(主键兌Q?-->
<!-- constrained(U束) (可? 表明该类对应的表对应的数据库表,
和被兌的对象所对应的数据库表之_通过一个外键引用对主键q行U束?br /> 而且它们之间的约束条件ؓtrue
在这里默认了两者的U联操作Q否则的话一方的主键׃ؓI没有Q何意义了 -->
<one-to-one name="idCard" constrained="true"/>
</class>
关于idCard的xml配置可以?br /> <!-- 默认Z键关?卛_载cardNo 时根据其主键?兌的Person表中 主键相同?元组
取出
默认的抓取策略ؓ Join -->
<one-to-one name="person"/>
当然也可以不用?/p>
7、extends
<!-- 试每个具体的类映射一U表Q这里Animal应该是抽象的Q所以不应该被生成出来,?
abstract="true"-->
<class name="Animal" abstract="true">
<id name="id">
<generator class="assigned"/>
</id>
<!-- 此处不需要鉴别器Q因为每个具体的c都生了一张表 -->
<property name="name" />
<property name="sex" />
<union-subclass name="Pig" table="t_pig">
<property name="weight"/>
</union-subclass>
<union-subclass name="Bird" table="t_bird">
<property name="height"/>
</union-subclass>
</class>
<!-- 试单表l承映射 -->
<class name="Animal" table="t_animal" lazy="false">
<id name="id">
<generator class="native"/>
</id>
<!-- discriminator 鉴别?用来识别不同的子c?-->
<discriminator column="type" type="string"/>
<property name="name" />
<property name="sex" />
<!-- Pig -->
<!-- discriminator-value的默认是完整的类?-->
<subclass name="Pig" discriminator-value="P">
<property name="weight"/>
</subclass>
<!-- Bird -->
<subclass name="Bird" discriminator-value="B">
<property name="height"/>
</subclass>
</class>
8、component lg映射试
componentcM是一个实体类Q在hibernate中的实体是指?一个Pojo+一个映文?br /> componentcL一个辅助类
component lg映射
<component name="contact" class="org.n2535.hibernate.Contact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
9、复合主?br />因ؓ主键是不可重复的Q所以在复合主键的类中我们实CSerializable接口Q?br />和hashcode、equalsҎQ能够确保主键的唯一性?br /> <!-- 复合主键映射我们也可以认为是一U?component lg映射的一U?-->
<composite-id name="pk">
<key-property name="productYear"/>
<key-property name="productMonth"/>
</composite-id>
<property name="name"/>
<property name="factory"/>
</class>
10、集合映?br />
<set name="setValue" table="t_set_value">
<key column="set_id"/>
<element type="string" column="set_value"/>
</set>
<list name="listValue" table="t_list_value">
<key column="list_id"/>
<!-- q里必须l出排序的烦引,因ؓlist是有序的Q下同) -->
<list-index column="list_index"/>
<element type="string" column="list_value"/>
</list>
<array name="arrayValue" table="t_array_value">
<key column="array_id"/>
<list-index column="array_index"/>
<element type="string" column="array_value"/>
</array>
<map name="mapValue" table="t_map_value">
<key column="map_id"/>
<map-key type="string" column="map_key"/>
<element type="string" column="map_value"/>
</map>
11、关于Hibernate的锁
1Q、悲观锁Q先获得数据库的锁的U程Q知道该U程攑ּ提交Q其他的U程无法修改该数据
QLockMode.UPGRADE Q利用数据库的for update子句加锁。)
2Q、乐观锁Q通常利用一?version 的版本冲H来实现Q实际上不是数据库的锁,一个线E的version
必须大于数据库中的version值才能被存储Q否则报错。这h供了比悲观锁宽松的条Ӟ只要 version
大于数据库中的version可以被存储Q而不会因为是否死一个线E先获得锁,因ؓ乐观锁根本就不是一
U锁?br /> * 未用悲观锁的时候,不同的操作可以访问相同的数据Q那么会造成数据的错?br /> * 使用悲观锁的时候,可以避免q个问题
可以不用昄的调用,如果用update那么在提交的时候会自动的updateQ当W一个操作将数据锁住
的时候,Q所有的其他讉K被止Q第二个select操作会dQ知道第一个操作释放了锁,W二?/p>
对象的选择操作会根据第一个对像的update的结果来d数据Q如果两个对象都从数据库中读取了相同
的数据,那么W一ơ的update操作Q将会被W二ơ的覆盖Q造成错误的数据?br /> session.update(inv);
要用悲观锁请用指定的数据库的命oQ或者用hibernate中的配置?br /> * 乐观锁采用的version的冲H机Ӟ如果update的version于或数据库中的version
* 会产生错误插入p|Q一位update的限制条件是Ҏ 主键和version 所以会p|
* 我们q能仿照 Hibernate 的乐观锁机制Q用Jdbc实现乐观?br />
12、hibernate查询语言hql
在hql中关键字不区分大写Q但是属性和cd区分大小?/p>
1)、简单属性查询【重要?br /> * 单一属性查询,q回l果集属性列表,元素cd和实体类中相应的属性类型一?br /> * 多个属性查?q回的集合元素是对象数组,数组元素的类型和对应的属性在实体cM的类?/p>
一?br /> 数组的长度取决与select中属性的个数
* 如果认ؓq回数组不够对象化,可以采用hql动态实例化Student对象
参见QSimplePropertyQueryTest.java
2)、实体对象查询【重要?br /> * N + 1问题Q在默认情况下,使用query.iterate查询Q有可以能出现N+1问题
所谓的N+1是在查询的时候发ZN+1条sql语句
1: 首先发出一条查询对象id列表的sql
N: Ҏid列表到缓存中查询Q如果缓存中不存在与之匹配的数据Q那么会Ҏid发出相应?/p>
sql语句
* list和iterate的区别?
* list每次都会发出sql语句Qlist会向~存中放入数据,而不利用~存中的数据
* iterateQ在默认情况下iterate利用~存数据Q但如果~存中不存在数据有可以能
出现N+1问题
参见QSimpleObjectQueryTest1.java/SimpleObjectQueryTest2.java
3)、条件查询【重要】?br /> * 可以采用拼字W串的方式传递参?br /> * 可以采用 Q来传递参敎ͼ索引?开始)
* 可以采用 :参数?来传递参?br /> * 如果传递多个参敎ͼ可以采用setParamterListҎ
* 在hql中可以用数据库的函敎ͼ如:date_format
参见QSimpleConditionQueryTest.java
4)、hibernate也支持直接用sqlq行查询
参见QSqlQueryTest.java
5)、外|命名查?br /> * 在映文件中采用<query>标签来定义hql
* 在程序中采用session.getNamedQuery()Ҏ得到hql查询?br /> 参见QStudent.hbm.xml、NameQueryTest.java
6)、查询过滤器
* 在映文件中定义qo器参?br /> * 在类的映中使用q些参数
* 在程序中启用qo?br /> 参见QStudent.hbm.xml、FilterQueryTest.java
7)、分|询【重要】?br /> * setFirstResult()Q从0开?br /> * setMaxResults,每页昄多少条数?br /> 参见QPageQueryTest.java
8)、对象导航查询,在hql中采?. q行D【重要?br /> 参见QObjectNavQueryTest.java
9)、连接查询【重要?br /> * 内连
* 外连接(左连?双接)
参见QJoinQueryTest.java
10)、统计查询【重要?br /> 参见QStatQueryTest.java
11)、DML风格的操作(量用Q因为和~存不同步)
参见QDMLQueryTest.java
13、Hibernate中的~存
1)、一U缓?br />session 中一U缓存的生命周期和session的相?br />׃load使用了session中的一U缓?所以第二次的load q不会发sql 因ؓ在session的缓存中q存?/p>
相同的数据?br />׃get使用了session中的一U缓?所以第二次的get q不会发sql 因ؓ在session的缓存中q存在相
同的数据?br /> 会发出查?id ?sqlQ用一U缓存才会发出) 但是不会发出查询对象?sql 因ؓIterate
查询支持~存?br />在save的时候会在缓存中保存一份当前对象的引用?br />session.clear();//全部清除
2Q、二U缓?br /> <!-- 指定二~存的提供?-->
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 指定是否使用二~存 默认为true -->
<property name="cache.use_second_level_cache">true</property>
使用ehcache.xmlq个配置文g来配|二U缓存?br />session 中二U缓存的生命周期和sessionFactory的相同,所以又UCؓ sessionFactory U缓存,二
~存只能用于存储实体?br />3Q、三U缓?
<!-- 使用查询~存 默认为false-->
<property name="cache.use_query_cache">true</property>
queryCache生命周期和sessionFactory的相同?br />但是在数据库里面的数据改变的时候,queryCache中的对象失效?br />QueryCache的生命周期与session无关?br />Iterate 接口不支?QueryCache?br />q里使用list 来查询实体对?q开启了QueryCache ׃QueryCache 会存储实体的主键|而list ?/p>
查询实体的时候不会用缓?所以list会用QueryCache的实体的主键?L询相应的Q实体,׃
它会现在~存中查扑֮体对?如果不存在则会发出sql到数据库中查?q里没有配置二~存 Q又?/p>
开了session所以在~存中不存在实体对象 所以会Ҏ在QueryCache 中的实体主键值发出sql到数据库
中查询?br />因ؓ开启了二~存QQueryCache 会存储查询出来的实体的主键,而list会根据在QueryCache中的 ?/p>
键值到二~存中查扄应的实体Q所以不会发出sqlQlist接口不会使用一U缓存但是能够利用这U方
法用QueryCache ?二~存Q?/p>
14、抓取策?br /> 1Q、fetch = "select" 抓取{略 发两个select语句Qfetch = "join" 抓取{略 使用外连?/p>
查询?br />2Q、在集合中的抓取{略
•?load
* fetch = "select" 抓取{略 发两条sql
* fetch = "join" 发一条sql 采用外连接查?br />•?HQL
* fetch = "select" 抓取{略 发两条sql 和加载对象方式一?每次每个实体的集合时会发sql
* fetch = "subselect" 会在查询实体的集合时将所有查询的实体的集合发一ơsql 全部查询出来
3Q、测?batch ?size
batch-size="3"在集合中讄?/p>