Contenu connexe
Similaire à Hibernate (20)
Hibernate
- 32. 业务逻辑代码与数据访问代码耦合的 saveCustomer() 方法 con=getConnection(); // 获得数据库连接 // 开始一个数据库事务 con.setAutoCommit(false); // 以下是业务逻辑代码,检查客户姓名是否为空 if(customer.getName()==null) throw new BusinessException(" 客户姓名不允许为空 "); // 以下是数据访问代码,持久化 Customer 对象 // 为新的 CUSTOMERS 记录分配惟一的 ID long customerId=getNextId(con,"CUSTOMERS"); // 把 Customer 对象映射为面向关系的 SQL 语句 stmt=con.prepareStatement("insert into CUSTOMERS(ID,NAME,AGE) values(?,?,?)"); stmt.setLong(1,customerId); stmt.setString(2,customer.getName()); stmt.setInt(3,customer.getAge()); stmt.execute();
- 33. 业务逻辑代码与数据访问代码耦合的 saveCustomer() 方法 Iterator iterator =customer.getOrders().iterator(); while (iterator.hasNext() ) { // 以下是业务逻辑代码,检查订单编号是否为空 Order order=(Order)iterator.next(); if(order.getOrderNumber()==null) throw new BusinessException(" 订单编号不允许为空 "); // 以下是数据访问代码,级联持久化 Order 对象 // 为新的 ORDERS 记录分配惟一的 ID long orderId=getNextId(con,"ORDERS"); // 把 Order 对象映射为面向关系的 SQL 语句 stmt=con.prepareStatement("insert into ORDERS(ID,ORDER_NUMBER,PRICE,CUSTOMER_ID)values(?,?,?,?)"); stmt.setLong(1,orderId); stmt.setString(2,order.getOrderNumber()); stmt.setDouble(3,order.getPrice()); stmt.setLong(4,customerId); stmt.execute(); } // 提交数据库事务 con.commit();
- 43. Hibernate 的配置文件 (hibernate.properties) hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect hibernate.connection.driver_class=com.mysql.jdbc.Driver hibernate.connection.url=jdbc:mysql://localhost:3306/SAMPLEDB hibernate.connection.username=root hibernate.connection.password=1234 hibernate.show_sql=true
- 46. 创建数据库 Schema create table CUSTOMERS ( ID bigint not null primary key, NAME varchar(15) not null, EMAIL varchar(128) not null, PASSWORD varchar(8) not null, PHONE int , ADDRESS varchar(255), SEX char(1) , IS_MARRIED bit, DESCRIPTION text, IMAGE blob, BIRTHDAY date, REGISTERED_TIME timestamp );
- 47. 创建对象 - 关系映射文件 Customer.hbm.xml <hibernate-mapping> <class name="mypack.Customer" table="CUSTOMERS"> <id name="id" column="ID" type="long"> <generator class="increment"/> </id> <property name="name" column="NAME" type="string" not-null="true" /> <property name="email" column="EMAIL" type="string" not-null="true" /> <property name="password" column="PASSWORD" type="string" not-null="true"/> <property name="phone" column="PHONE" type="int" /> <property name="address" column="ADDRESS" type="string" /> <property name="sex" column="SEX" type="character"/> …… </class> </hibernate-mapping>
- 56. Hibernate 的初始化 static{ try{ // 根据默认位置的 Hibernate 配置文件的配置信息,创建一个 //Configuration 实例 Configuration config = new Configuration(); config.addClass(Customer.class); // 创建 SessionFactory 实例 */ sessionFactory = config.buildSessionFactory(); }catch(Exception e){e.printStackTrace();} }
- 61. 用 Session 来执行事务的流程 Session session = factory.openSession(); Transaction tx; try { // 开始一个事务 tx = session.beginTransaction(); // 执行事务 ... // 提交事务 tx.commit(); } catch (Exception e) { // 如果出现异常,就撤销事务 if (tx!=null) tx.rollback(); throw e; } finally { // 不管事务执行成功与否,最后都关闭 Session session.close(); }
- 75. 映射 Order 类: Order.hbm.xml <class name="mypack.Order" table="ORDERS"> <id name="id" type="long" column="ID"> <generator class="increment"/> </id> <property name="orderNumber" type="string" > <column name="ORDER_NUMBER" length="15" /> </property> <many-to-one name="customer" column="CUSTOMER_ID" class="mypack.Customer" /> </class> Order 类的 orderNumber 属性为值类型,而 customer 属性为实体类型,实体类型具有单独的 OID 。
- 77. 映射 Customer 类: Customer.hbm.xml <class name="mypack.Customer" table="CUSTOMERS" > <id name="id" type="long" column="ID"> <generator class="increment"/> </id> <property name="name" type="string" > <column name="NAME" length="15" /> </property>
- 78. 映射 Customer 类: Customer.hbm.xml (续) <set name="orders" cascade="save-update" inverse= " true" > <key column="CUSTOMER_ID" /> <one-to-many class="mypack.Order" /> </set> </class>
- 81. 级联 保存 Customer 和 Order 对象 tx = session.beginTransaction(); Customer customer=new Customer("Tom",new HashSet()); Order order=new Order(); order.setOrderNumber("Tom_Order001"); // 建立双向关联关系 order.setCustomer(customer); customer.getOrders().add(order); session.save(customer); tx.commit();
- 82. Hibernate 实用工具 Java 源文件 数据库 Schema 对象 - 关系映射文件 hbm2java XDoclet hbm2ddl Middlegen
- 83. 在 build.xml 中定义 codegen target <target name="codegen" depends="prepare" description="Generate Java source from the O/R mapping files"> <taskdef name="hbm2java" lassname="net.sf.hibernate.tool.hbm2java.Hbm2JavaTask" classpathref="project.class.path"/> <hbm2java output="${source.root}"> <fileset dir="${source.root}"> <include name="**/*.hbm.xml"/> </fileset> </hbm2java> </target>
- 84. 在 build.xml 中定义 schema target <target name="schema" depends="compile" description="Generate DB schema from the O/R mapping files"> <taskdef name="schemaexport" classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask" classpathref="project.class.path"/> <schemaexport properties="${class.root}/hibernate.properties“ quiet="no" text="no" drop="no" output="${schema.dir}/sampledb.sql" delimiter=";"> <fileset dir="${class.root}"> <include name="**/*.hbm.xml"/> </fileset> </schemaexport> </target>
- 87. Category 类的源程序 public class Category implements Serializable{ …… private Category parentCategory; private Set childCategories=new HashSet(); public Category getParentCategory(){ return parentCategory; } public void setParentCategory(Category parentCategory){ this.parentCategory=parentCategory; } public Set getChildCategories(){ return childCategories; } public void setChildCategories(Set childCategories){ this.childCategories=childCategories; } }
- 90. 映射 parentCategory 属性 <many-to-one name="parentCategory" column="CATEGORY_ID" class="mypack.Category" />
- 91. 映射 childCategories 属性 <set name="childCategories" cascade=" all-delete-orphan " inverse="true" > <key column="CATEGORY_ID" /> <one-to-many class="mypack.Category" /> </set>
- 95. 理解 Session 的缓存 tx = session.beginTransaction(); Customer c1=new Customer("Tom",new HashSet()); //Customer 对象被持久化,并且加入到 Session 的缓存中 session.save(c1); Long id=c1.getId(); //c1 变量不再引用 Customer 对象 c1=null; // 从 Session 缓存中读取 Customer 对象,使 c2 变量引用 Customer 对象 Customer c2=(Customer)session.load(Customer.class,id); tx.commit(); // 关闭 Session ,清空缓存 session.close(); // 访问 Customer 对象 System.out.println(c2.getName()); // c2 变量不再引用 Customer 对象 , 此时 Customer 对象结束生命周期。 c2=null;
- 96. 理解 Session 的缓存 tx = session.beginTransaction(); Customer c1=(Customer)session.load(Customer.class,new Long(1)); Customer c2=(Customer)session.load(Customer.class,new Long(1)); System.out.println(c1==c2); tx.commit(); session.close();
- 105. 用 Session 的 update() 方法关联游离对象 Customer customer=new Customer(); customer.setName("Tom"); Session session1=sessionFactory.openSession(); Transaction tx1 = session1.beginTransaction(); session1.save(customer); tx1.commit(); session1.close(); // 此时 Customer 对象变为游离对象 Session session2=sessionFactory.openSession(); Transaction tx2 = session1.beginTransaction(); customer.setName("Linda") // 在和 session2 关联之前修改 Customer 对象的属性 session2.update(customer); customer.setName("Jack"); // 在和 session2 关联之后修改 Customer 对象的属性 tx2.commit(); session2.close();
- 115. 访问没有被初始化的游离状态的集合代理类实例 Session session=sessionFactory.openSession(); tx = session.beginTransaction(); Customer customer=(Customer)session.get(Customer.class,new Long(1)); tx.commit(); session.close(); // 抛出异常 Iterator orderIterator=customer.getOrders().iterator(); 执行以上代码,会抛出以下异常: ERROR LazyInitializer:63 - Exception initializing proxy
- 125. HQL 检索步骤 // 创建一个 Query 对象 Query query=session.createQuery("from Customer as c where " +" c.name=:customerName " +"and c.age=:customerAge " ); // 动态绑定参数 query.setString( "customerName","Tom" ); query.setInteger( "customerAge",21 ); // 执行查询语句,返回查询结果 List result= query.list();
- 129. QBC 检索方式 // 创建一个 Criteria 对象 Criteria criteria=session.createCriteria(Customer.class); // 设定查询条件,然后把查询条件加入到 Criteria 中 Criterion criterion1= Expression.like("name", "T%") ; Criterion criterion2= Expression.eq("age", new Integer(21)) ; criteria=criteria.add(criterion1); criteria=criteria.add(criterion2); // 执行查询语句,返回查询结果 List result=criteria.list();
- 131. 方法链编程风格 List result=session.createCriteria(Customer.class) .add(Expression.like("name", "T%") .add(Expression.eq("age", newInteger(21)) .list();
- 134. 分页查询 // 采用 HQL 检索方式 Query query = session.createQuery("from Customer c order by c.name asc"); query.setFirstResult(0); query.setMaxResults(10); List result = query.list(); // 采用 QBC 检索方式 Criteria criteria = session.createCriteria( Customer.class); criteria.addOrder( Order.asc("name") ); criteria.setFirstResult(0); criteria.setMaxResults(10); List result = criteria.list();
- 152. 并发运行的两个事务导致脏读 取款事务在 T5 时刻把存款余额改为 900 元,支票转账事务在 T6 时刻查询账户的存款余额为 900 元,取款事务在 T7 时刻被撤销,支票转账事务在 T8 时刻把存款余额改为 1000 元。 由于支票转账事务查询到了取款事务未提交的更新数据,并且在这个查询结果的基础上进行更新操作,如果取款事务最后被撤销,会导致银行客户损失 100 元。
- 153. 并发运行的两个事务导致第二类丢失更新 取款事务在 T5 时刻根据在 T3 时刻的查询结果,把存款余额改为 1000-100 元,在 T6 时刻提交事务。支票转账事务在 T7 时刻根据在 T4 时刻的查询结果,把存款余额改为 1000+100 元。由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失 100 元。
- 163. 使用悲观锁 Account account=(Account)session.get (Account.class,new Long(1), LockMode.UPGRADE ); account.setBalance(account.getBalance()-100); Hibernate 执行的 select 语句为 : select * from ACCOUNTS where ID=1 for update ; update ACCOUNTS set BALANCE=900…
- 171. 利用 <version> 元素对 ACCOUNTS 表中记录进行版本控制 try { tx = session.beginTransaction(); log.write("transferCheck(): 开始事务 "); Thread.sleep(500); Account account=(Account)session.get(Account.class,new Long(1)); log.write("transferCheck(): 查询到存款余额为: balance="+account.getBalance()); Thread.sleep(500); account.setBalance(account.getBalance()+100); log.write("transferCheck(): 汇入 100 元,把存款余额改为: "+account.getBalance()); tx.commit(); // 当 Hibernate 执行 update 语句时,可能会抛出 StaleObjectException log.write("transferCheck(): 提交事务 "); Thread.sleep(500); } catch(StaleObjectStateException e) { if (tx != null) { tx.rollback(); } e.printStackTrace(); System.out.println(" 账户信息已被其他事务修改 , 本事务被撤销,请重新开始支票转账事务 "); log.write("transferCheck(): 账户信息已被其他事务修改 , 本事务被撤销 "); }
- 182. 粗粒度关系数据模型 create table CUSTOMERS ( ID bigint not null, NAME varchar(15), HOME_STREET varchar(255), HOME_CITY varchar(255), HOME_PROVINCE varchar(255), HOME_ZIPCODE varchar(255), COM_STREET varchar(255), COM_CITY varchar(255), COM_PROVINCE varchar(255), COM_ZIPCODE varchar(255), primary key (ID));
- 186. 持久化 Customer 对象 tx = session.beginTransaction(); Customer customer=new Customer(); Address homeAddress=new Address("province1","city1","street1","100001",customer); Address comAddress=new Address("province2","city2","street2","200002",customer); customer.setName("Tom"); customer.setHomeAddress(homeAddress); customer.setComAddress(comAddress); session.save(customer); tx.commit();
- 197. 业务代理接口 INetstoreService public interface INetstoreService extends IAuthentication { /** 批量检索 Item 对象, beginIndex 参数指定查询结果的起始位置, length 指定检索的 Item 对象的数目。对于 Item 对象的所有集合属性,都使用延迟检索策略 */ public List getItems(int beginIndex,int length) throws DatastoreException; /** 根据 id 加载 Item 对象 */ public Item getItemById( Long id ) throws DatastoreException; /** 根据 id 加载 Customer 对象,对于 Customer 对象的 orders 属性,显式采用迫切左外连接检 索策略 */ public Customer getCustomerById( Long id ) throws DatastoreException; /** 保存或者更新 Customer 对象,并且级联保存或更新它的 orders 集合中的 Order 对象 */ public void saveOrUpdateCustomer(Customer customer ) throws DatastoreException; /** 保存订单 */ public void saveOrder(Order order) throws DatastoreException; public void setServletContext( ServletContext ctx ); public void destroy(); }
- 198. IAuthentication 接口 public interface IAuthentication { /** 登出 Web 应用 */ public void logout(String email); /** 根据客户的 email 和 password 验证身份,如果验证成功,返回 匹配的 Customer 对象,它的 orders 集合属性采用延迟检索策略, 不会被初始化 */ public Customer authenticate(String email, String password) throws InvalidLoginException, ExpiredPasswordException,AccountLockedException, DatastoreException; }
- 199. NetstoreServiceImpl 的 authenticate() 方法 tx = session.beginTransaction(); // 对与 Customer 关联的 Order 对象采用延迟检索策略 Query query = session.createQuery("from Customer c where c.email=:email and c.password=:password"); query.setString("email",email); query.setString("password",password); List result = query.list(); tx.commit(); if(result.isEmpty()) throw new InvalidLoginException(); return (Customer)result.iterator().next();
- 200. NetstoreServiceImpl 的 getCustomerById() 方法 tx = session.beginTransaction(); // 对与 Customer 关联的 Order 对象采用迫切左外连接检索策略 Query query = session.createQuery("from Customer c left outer join fetch c.orders where c.id=:id"); query.setLong("id",id.longValue()); Customer customer =(Customer) query.uniqueResult(); tx.commit(); return customer;
- 203. NetstoreServiceFactory 的 init() 方法 public void init(ActionServlet servlet, ModuleConfig config) throws ServletException{ this.servlet = servlet; // 把服务工厂类本身的实例保存到 application 范围中 servlet.getServletContext().setAttribute( IConstants.SERVICE_FACTORY_KEY, this ); }
- 204. NetstoreServiceFactory 的 createService() 方法 public INetstoreService createService() throws ClassNotFoundException, IllegalAccessException, InstantiationException { // 从 web.xml 中读取 ActionServlet 的初始化参数 netstore-service-class String className = servlet.getInitParameter( IConstants.SERVICE_CLASS_KEY ); if (className != null ){serviceClassname = className;} // 构造业务代理类实例 INetstoreService instance = (INetstoreService)Class.forName(serviceClassname).newInstance(); instance.setServletContext( servlet.getServletContext() ); return instance; }
- 207. LoginAction 类的 execute() 方法 String email = ((LoginForm)form).getEmail(); String password = ((LoginForm)form).getPassword(); ServletContext context = getServlet().getServletContext(); // 获得业务代理类实例, serviceImpl 被声明为业务代理接口类型,当 INetstoreService 接 // 口的实现发生改变时,不对 Action 类的程序代码构成任何影响。 //getNetstoreService() 方法在 LoginAction 的父类 NetstoreBaseAction 中定义 INetstoreService serviceImpl = getNetstoreService(); // 调用业务代理类的业务方法 Customer customer= serviceImpl.authenticate(email, password); SessionContainer existingContainer = getSessionContainer(request); existingContainer.setCustomer(customer); return mapping.findForward(IConstants.SUCCESS_KEY);
- 208. NetstoreBaseAction 类的 getNetstoreService() 方法 protected INetstoreService getNetstoreService(){ // 从 application 范围内获得代理类工厂 INetstoreServiceFactory factory = (INetstoreServiceFactory)getApplicationObject( IConstants.SERVICE_FACTORY_KEY ); INetstoreService service = null; try{ // 构造代理类实例 service = factory.createService(); }catch( Exception ex ){ log.error( "Problem creating the Netstore Service", ex ); } return service; }