﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-jimingminlovefly-文章分类-hibernate</title><link>http://www.blogjava.net/jimingminlovefly/category/50450.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 30 Jan 2015 15:59:30 GMT</lastBuildDate><pubDate>Fri, 30 Jan 2015 15:59:30 GMT</pubDate><ttl>60</ttl><item><title>深入研究java.lang.ThreadLocal类</title><link>http://www.blogjava.net/jimingminlovefly/articles/422575.html</link><dc:creator>计明敏</dc:creator><author>计明敏</author><pubDate>Fri, 30 Jan 2015 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/jimingminlovefly/articles/422575.html</guid><wfw:comment>http://www.blogjava.net/jimingminlovefly/comments/422575.html</wfw:comment><comments>http://www.blogjava.net/jimingminlovefly/articles/422575.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jimingminlovefly/comments/commentRss/422575.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jimingminlovefly/services/trackbacks/422575.html</trackback:ping><description><![CDATA[<div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">一、概述</strong></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;"></strong>&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">ThreadLocal是什么呢？其实ThreadLocal并非是一个线程的本地实现版本，它并不是一个Thread，而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单，就是为每一个使用该变量的线程都提供一个变量值的副本，是Java中一种较为特殊的线程绑定机制，是每一个线程都可以独立地改变自己的副本，而不会和其它线程的副本冲突。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">从线程的角度看，每个线程都保持一个对其线程局部变量副本的隐式引用，只要线程是活动的并且 ThreadLocal 实例是可访问的；在线程消失之后，其线程局部实例的所有副本都会被垃圾回收（除非存在对这些副本的其他引用）。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">通过ThreadLocal存取的数据，总是与当前线程相关，也就是说，JVM 为每个运行的线程，绑定了私有的本地实例存取空间，从而为多线程环境常出现的并发访问问题提供了一种隔离机制。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单，在ThreadLocal类中有一个Map，用于存储每一个线程的变量的副本。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">概括起来说，对于多线程资源共享的问题，同步机制采用了&#8220;以时间换空间&#8221;的方式，而ThreadLocal采用了&#8220;以空间换时间&#8221;的方式。前者仅提供一份变量，让不同的线程排队访问，而后者为每一个线程都提供了一份变量，因此可以同时访问而互不影响。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">二、API说明</strong></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">ThreadLocal()</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建一个线程本地变量。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">T get()</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回此线程局部变量的当前线程副本中的值，如果这是线程第一次调用该方法，则创建并初始化此副本。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">protected&nbsp; T initialValue()</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次，即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法，则不会在线程中再调用 initialValue 方法。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;&nbsp; 若该实现只返回 null；如果程序员希望将线程局部变量初始化为 null 以外的某个值，则必须为 ThreadLocal 创建子类，并重写此方法。通常，将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法，并返回新构造的对象。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">void remove()</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量，那么在默认情况下它将拥有其 initialValue。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">void set(T value)</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能，它们只依赖于 initialValue() 方法来设置线程局部变量的值。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">在程序中一般都重写initialValue方法，以给定一个特定的初始值。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">三、典型实例</strong></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">1、Hiberante的Session 工具类HibernateUtil</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">这个类是Hibernate官方文档中HibernateUtil类，用于session管理。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><div style="margin: 0px;"><div style="padding: 5px; margin: 0px; border: 1px solid #aaaaaa; background-color: #f5f5f5;"><div style="margin: 0px;">public class HibernateUtil {</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; private static Log log = LogFactory.getLog(HibernateUtil.class);</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; private static final SessionFactory sessionFactory;&nbsp;&nbsp;&nbsp;&nbsp; //定义SessionFactory</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; static {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 通过默认配置文件hibernate.cfg.xml创建SessionFactory<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sessionFactory = new Configuration().configure().buildSessionFactory();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Throwable ex) {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log.error("初始化SessionFactory失败！", ex);<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ExceptionInInitializerError(ex);<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }</div><div style="margin: 0px;"><br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; //创建线程局部变量session，用来保存Hibernate的Session<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; public static final ThreadLocal session = new ThreadLocal();</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; /**<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp; * 获取当前线程中的Session<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp; * @return Session<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp; * @throws HibernateException<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp; */<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; public static Session currentSession() throws HibernateException {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session s = (Session) session.get();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 如果Session还没有打开，则新开一个Session<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (s == null) {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = sessionFactory.openSession();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.set(s);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //将新开的Session保存到线程局部变量中<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return s;<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; public static void closeSession() throws HibernateException {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取线程局部变量，并强制转换为Session类型<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session s = (Session) session.get();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.set(null);<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (s != null)<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s.close();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />}</div></div></div></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">在这个类中，由于没有重写ThreadLocal的initialValue()方法，则首次创建线程局部变量session其初始值为null，第一次调用currentSession()的时候，线程局部变量的get()方法也为null。因此，对session做了判断，如果为null，则新开一个Session，并保存到线程局部变量session中，这一步非常的关键，这也是&#8220;public static final ThreadLocal session = new ThreadLocal()&#8221;所创建对象session能强制转换为Hibernate Session对象的原因。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">2、另外一个实例</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">创建一个Bean，通过不同的线程对象设置Bean属性，保证各个线程Bean对象的独立性。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><div style="margin: 0px;"><div style="margin: 0px;"><div style="margin: 0px;"><div style="margin: 0px;"><div style="margin: 0px;"><div style="margin: 0px;"><div style="padding: 5px; margin: 0px; border: 1px solid #aaaaaa; background-color: #f5f5f5;"><div style="margin: 0px;">/**<br style="padding: 0px; margin: 0px;" />&nbsp;* Created by IntelliJ IDEA.<br style="padding: 0px; margin: 0px;" />&nbsp;* User: leizhimin<br style="padding: 0px; margin: 0px;" />&nbsp;* Date: 2007-11-23<br style="padding: 0px; margin: 0px;" />&nbsp;* Time: 10:45:02<br style="padding: 0px; margin: 0px;" />&nbsp;* 学生<br style="padding: 0px; margin: 0px;" />&nbsp;*/<br style="padding: 0px; margin: 0px;" />public class Student {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; private int age = 0;&nbsp;&nbsp; //年龄</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; public int getAge() {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.age;<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; public void setAge(int age) {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.age = age;<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />}</div></div></div></div></div></div></div></div></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><div style="margin: 0px;"><div style="margin: 0px;"><div style="padding: 5px; margin: 0px; border: 1px solid #aaaaaa; background-color: #f5f5f5;"><div style="margin: 0px;">/**<br style="padding: 0px; margin: 0px;" />&nbsp;* Created by IntelliJ IDEA.<br style="padding: 0px; margin: 0px;" />&nbsp;* User: leizhimin<br style="padding: 0px; margin: 0px;" />&nbsp;* Date: 2007-11-23<br style="padding: 0px; margin: 0px;" />&nbsp;* Time: 10:53:33<br style="padding: 0px; margin: 0px;" />&nbsp;* 多线程下测试程序<br style="padding: 0px; margin: 0px;" />&nbsp;*/<br style="padding: 0px; margin: 0px;" />public class ThreadLocalDemo implements Runnable {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; //创建线程局部变量studentLocal，在后面你会发现用来保存Student对象<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; private final static ThreadLocal studentLocal = new ThreadLocal();</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; public static void main(String[] agrs) {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadLocalDemo td = new ThreadLocalDemo();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread t1 = new Thread(td, "a");<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread t2 = new Thread(td, "b");<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t1.start();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t2.start();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; public void run() {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; accessStudent();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; /**<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp; * 示例业务方法，用来测试<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp; */<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; public void accessStudent() {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取当前线程的名字<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String currentThreadName = Thread.currentThread().getName();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(currentThreadName + " is running!");</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //产生一个随机数并打印<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Random random = new Random();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int age = random.nextInt(100);<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("thread " + currentThreadName + " set age to:" + age);</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取一个Student对象，并将随机数年龄插入到对象属性中<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Student student = getStudent();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; student.setAge(age);<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(500);<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (InterruptedException ex) {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }</div><div style="margin: 0px;">&nbsp;</div><div style="margin: 0px;">&nbsp;&nbsp;&nbsp; protected Student getStudent() {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取本地线程变量并强制转换为Student类型<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Student student = (Student) studentLocal.get();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //线程首次执行此方法的时候，studentLocal.get()肯定为null<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (student == null) {<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //创建一个Student对象，并保存到本地线程变量studentLocal中<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; student = new Student();<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; studentLocal.set(student);<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return student;<br style="padding: 0px; margin: 0px;" />&nbsp;&nbsp;&nbsp; }<br style="padding: 0px; margin: 0px;" />}</div></div></div></div></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">运行结果：</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><div style="margin: 0px;"><div style="padding: 4px; margin: 0px; border: 1px solid #cccccc; font-size: 10pt; width: 705.59375px; color: #000000; word-break: break-all; line-height: 16px; font-family: verdana, 宋体; background-color: #eeeeee;">a is running!&nbsp;<br style="padding: 0px; margin: 0px;" />thread a set age to:76&nbsp;<br style="padding: 0px; margin: 0px;" />b is running!&nbsp;<br style="padding: 0px; margin: 0px;" />thread b set age to:27&nbsp;<br style="padding: 0px; margin: 0px;" />thread a first read age is:76&nbsp;<br style="padding: 0px; margin: 0px;" />thread b first read age is:27&nbsp;<br style="padding: 0px; margin: 0px;" />thread a second read age is:76&nbsp;<br style="padding: 0px; margin: 0px;" />thread b second read age is:27&nbsp;</div></div></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">可以看到a、b两个线程age在不同时刻打印的值是完全相同的。这个程序通过妙用ThreadLocal，既实现多线程并发，游兼顾数据的安全性。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">四、总结</strong></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;"></strong>&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本，通过访问副本来运行业务，这样的结果是耗费了内存，单大大减少了线程同步所带来性能消耗，也减少了线程并发控制的复杂度。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">ThreadLocal不能使用原子类型，只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制，使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本，使得每个线程在某一时间访问到的并不是同一个对象，这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反，它用于在多个线程间通信时能够获得数据共享。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">Synchronized用于线程间的数据共享，而ThreadLocal则用于线程间的数据隔离。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制，比ThreadLocal更加复杂。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">五、ThreadLocal使用的一般步骤</strong></div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">1、在多线程的类（如ThreadDemo类）中，创建一个ThreadLocal对象threadXxx，用来保存线程间需要隔离处理的对象xxx。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">2、在ThreadDemo类中，创建一个获取要隔离访问的数据的方法getXxx()，在方法中判断，若ThreadLocal对象为null时候，应该new()一个隔离访问类型的对象，并强制转换为要应用的类型。</div><div style="margin: 0px; color: #555555; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">3、在ThreadDemo类的run()方法中，通过getXxx()方法获取要操作的数据，这样可以保证每个线程对应一个数据对象，在任何时刻都操作的是这个对象。</div><div></div><br /><br /><br /><br /><br /><br /></div><img src ="http://www.blogjava.net/jimingminlovefly/aggbug/422575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jimingminlovefly/" target="_blank">计明敏</a> 2015-01-30 11:07 <a href="http://www.blogjava.net/jimingminlovefly/articles/422575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate-jpa-pdf.rar</title><link>http://www.blogjava.net/jimingminlovefly/articles/378912.html</link><dc:creator>计明敏</dc:creator><author>计明敏</author><pubDate>Wed, 23 May 2012 02:07:00 GMT</pubDate><guid>http://www.blogjava.net/jimingminlovefly/articles/378912.html</guid><wfw:comment>http://www.blogjava.net/jimingminlovefly/comments/378912.html</wfw:comment><comments>http://www.blogjava.net/jimingminlovefly/articles/378912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jimingminlovefly/comments/commentRss/378912.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jimingminlovefly/services/trackbacks/378912.html</trackback:ping><description><![CDATA[<a href="http://www.blogjava.net/Files/jimingminlovefly/hibernate-jpa-pdf.rar"><font color="#002c99">hibernate-jpa-pdf.rar</font></a> <img src ="http://www.blogjava.net/jimingminlovefly/aggbug/378912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jimingminlovefly/" target="_blank">计明敏</a> 2012-05-23 10:07 <a href="http://www.blogjava.net/jimingminlovefly/articles/378912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Hibernate中 cascade 与 inverse 的理解-[转]</title><link>http://www.blogjava.net/jimingminlovefly/articles/377508.html</link><dc:creator>计明敏</dc:creator><author>计明敏</author><pubDate>Mon, 07 May 2012 02:15:00 GMT</pubDate><guid>http://www.blogjava.net/jimingminlovefly/articles/377508.html</guid><wfw:comment>http://www.blogjava.net/jimingminlovefly/comments/377508.html</wfw:comment><comments>http://www.blogjava.net/jimingminlovefly/articles/377508.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jimingminlovefly/comments/commentRss/377508.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jimingminlovefly/services/trackbacks/377508.html</trackback:ping><description><![CDATA[<span id="articlecontent" style="width: 740px"> 
<div>
<div id="app-share-container">
<div id="app-share-content">
<div>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">关于Hibernate中 cascade 与 inverse 的理解。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">您买的Hibernate书是哪一本呢？ 孙卫琴的精通Hibernate，还是 深入浅出Hibernate还是那本。。。<br />我是两本都买了，总体来说还可以，但是，有的地方讲的比较书面化，比如inverse这属性。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">在学习Hibernate的过程中最不好理解的就是这两个属性了。<br />(我当初学习Hibernate的时候，发现网上介绍这两个属性的文章倒是不少，但是，居然有好多都是转帖。。。还有的就是 照书搬~~-_-!!!)。。。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">据个例子：书上说inverse=false时，由主控方维持关系。。。<br />由于我也是初学者。。。再加上语文水平偏低。。。不理解&#8220;维持关系是啥意思&#8221;囧~</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">提示：<br />(1)如果：您不了解Hibernate的one-to-many或many-to-one的概念。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">(2)如果：你不了解Hibernate的&#8220;自由态&#8221;&#8220;持久态&#8221;&#8220;游离态&#8221;的概念。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">(3)如果：您不了解Hibernate中的&#8220;脏数据&#8221;的概念。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">(4)如果：您对Hibernate中Session缓存，没有初步了解的话。<br />(在Hibernate中调用save进行存储数据的时候,并不是马上就对数据库进行insert操作，而是会将其&#8220;数据对象(vo)&#8221;纳入Hibernate的Session缓存。)</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">在上面的4条提示中，如果您对其中的某一条，不是很清楚的话。希望请先了解有关知识。<br />否则，可能您将 &#8220;无法或很难&#8221;理解 cascade 或 inverse 这2个属性。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">首相，cascade 与 inverse 这两个属性，其实是完全不同的两个东西，想要了解他们各自的&#8220;用途与区别&#8221;，详见如下介绍：</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">这里有两个表:</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">（1）class&nbsp;&nbsp; (班级表)<br />相应字段：<br />cid&nbsp;&nbsp;&nbsp; varchar(32) 主键 not-null (班级id)<br />cname varchar(16)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; not-null (班级名称)&nbsp;&nbsp; <br /><br />（2）student (学生表)<br />相应字段：<br />sid&nbsp;&nbsp;&nbsp; varchar(32) 主键 not-null (学生id)<br />sname varchar(16)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; not-null (学生姓名)<br />class_id varchar(32)&nbsp;&nbsp; not-null (学生所属班级)</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">一个班级(class)对应多个学生(student)，所以班级表(class)就是&#8220;one-to-many&#8221;端<br />反之student就是many-to-one</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">//--------Class类的代码--------<br />public class Class implements.....<br />{<br />private cId = "";<br />private cName = "";<br />private students = java.util.HashMap();<br />// 省略对应的 geter setter<br />}<br />//--------Class.hbm.xml--------<br />&lt;hibernate-mapping&gt;<br />&lt;class name="lcx.vo.Class" table="class"<br />&nbsp;&nbsp; catalog="demo"&gt;<br />&nbsp;&nbsp; &lt;id name="cid" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp; &lt;column name="cid" length="32" /&gt;<br />&nbsp;&nbsp;&nbsp; &lt;generator class="uuid.hex" /&gt;<br />&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp; &lt;property name="name" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp; &lt;column name="cname" length="16" not-null="true" /&gt;<br />&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp; &lt;set name="students" table="student" cascade="save-update"&gt;<br />&nbsp;&nbsp;&nbsp; &lt;key column="class" /&gt;<br />&nbsp;&nbsp;&nbsp; &lt;one-to-many class="lcx.vo.Student" /&gt;<br />&nbsp;&nbsp; &lt;/set&gt; <br />&lt;/class&gt;<br />&lt;/hibernate-mapping&gt;</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">//--------Student类的代码;*******<br />public class Student implements.....<br />{<br />private sId = "";<br />private sName = "";<br />private Class class = null;<br />// 省略对应的 geter setter<br />}<br />// Student.hbm.xml<br />&lt;hibernate-mapping&gt;<br />&lt;class name="lcx.vo.Student" table="student" catalog="demo"&gt;<br />&nbsp;&nbsp; &lt;id name="cid" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp; &lt;column name="sid" length="32" /&gt;<br />&nbsp;&nbsp;&nbsp; &lt;generator class="uuid.hex" /&gt;<br />&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp; &lt;many-to-one name="class" <br />&nbsp;&nbsp;&nbsp; class="lcx.vo.Class"<br />&nbsp;&nbsp;&nbsp; column="class_id" <br />&nbsp;&nbsp;&nbsp; not-null="true" <br />&nbsp;&nbsp; /&gt;&nbsp;&nbsp;&nbsp;<br />&lt;/class&gt;<br />&lt;/hibernate-mapping&gt;</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">（一） cascade 的介绍：<br />当Hibernate持久化一个&#8220;临时对象(也叫自由态对象)&#8221;时，在默认的情况下(即：没有设置cascade属性或cascade=none时)，Hibernate不会自动&#8220;持久化他所关联&#8221;的其他临时对象。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">其中几种最常用的级联为<br />1,all:所有操作都传递到子实体-<br />-保存,更新,删除.<br />2,sav-update:保存和更新.<br />3,delete:删除.<br />4,delete-orphan:所有操作都传递到子实体,并删除不再与对象关联的对象.<br />hibernate不将级联传递到数据库它只在内部管理级联 <br /></span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">上面这些话是什么意思呢？ 什么叫不会自动 &#8220;持久化&#8221;关联的临时对象呢？</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">看如下代码：</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">// 创建一个 临时对象(也叫自由态对象) <br />// 也就是说这个 class 没有被Hibernate纳入Session缓存管理。<br />Class class = new Class();<br />//class.id 为自动生成<br />class.setName("一年级1班");</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">Student stu = new Student();<br />//student.id 为自动生成<br />stu.setName("小白兔");<br />stu.setClass(class);</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">// 关键就是这里。。。<br />class.getStudents().add(stu);</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">session.save(class);<br />// 提交</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">// 注意: Class.hbm.xml文件中,cascade="save-update"并且也没有设置inverse属性,也就是说inverse=false;<br />// 此时如果你开启了Hibernate的显示HQL语句功能，那么控制台将会显示如下3条HQL：</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">//----------------------------------------********<br />insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年级1班)<br />insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔, 66666666666666666666666666666666)<br />update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888<br />//----------------------------------------********</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">那么为什么会出现，这3条HQL语句呢，我们来一一分析一下：</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">第1条HQL语句:<br />其实第一条HQL比较好理解，<br />当我们调用 session.save(class) 后，在Hibernate进行提交的时候，<br />会发现&#8220;有&#8221;一条&#8220;新&#8221;的数据要插入(insert)，所以就往class表中,插入了这条新的class记录。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">第2条HQL语句：<br />注意问题就在这里：<br />这里为什么又出现了一条insert语句呢？而且还是向student表中插入数据。<br />我们在上面的代码中，并没有编写类似&#8220;session.save(student)&#8221;这样的语句啊。<br />这是为什么呢？<br />其实原因，是这么回事：因为我们在class端，设置了"级联更新"(即:cascade="save-update")，<br />也就是说，当Hibernate在向class表中插入&#8220;新&#8221;对象记录时，会检查&#8220;Class对象&#8221;所关联的属性(就是&lt;set&gt;对应的属性)，是否发生过变化，如果发生了变化，就按照&#8220;级联属性(cascade)&#8221;所设定的内容<br />进行操作。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">上面讲的这句话到底是什么意思呢？<br />用你们&#8220;人&#8221;话说，就是：<br />因为调用了 class.getStudents().add(stu);<br />所以，在Hibernate在进行插入 class对象的时候，发现class对象，所关联的集合中，有一条<br />&#8220;自由态&#8221;的对象，而又因为class端设置了&#8220;级联属性cascade&#8221;，所以，在插入这条 &#8220;新class对象&#8221;时，也一同把他内部的那些，还属于&#8220;自由态&#8221;的其他对象，也一同插入到，他们所对应的表中去了。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">还是不明白的话。。。可以看看。孙卫琴的《精通Hibernate》，在书上的第149页有。<br />但是关于inverse的介绍。。。写的就有些书面化了，如果语文不好的话。。。就难懂咯~</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">第3条HQL语句：<br />第三条HQL语句是一条update语句，是不是觉得，很莫名其妙。。。。<br />Hibernate大脑进水了吧，怎么吃饱了撑得，重复更新记录啊啊啊啊啊<br />假如：我们把 class端的配置文档中的 invser属性设置为true(即：inverse=true)<br />在执行上面的程序，发现，就变成2条insert语句啦。。。。。(update没啦。。。)<br />看来第三条的update语句和inverse有着密切的关系（他两有一腿~）。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">所以我们下边，就来介绍一下inverse属性:</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">当调用 Class.getStudents().add(stu)方法，进行添加操作时， <br />(即：向 "这个Class对象"所属的&#8220;集合 (也就是调用getStudents方法所返回的那个Set集合)&#8221;中添加一个Student(即 add(stu))，也就是说，这个&#8220;新&#8221;添加的Student对象(stu)， <br />他的Student.class_id字段&#8220;必须&#8221;，要等于&#8220;被添加方Class&#8221;的主键(即:Class.cid)。 <br />从&#8220;数据库&#8221;层面来讲，也就是说，这个&#8220;新&#8221;添加的&#8220;Student&#8221;的class_id字段，必须要与&#8220;Class&#8221;的cid字段，存在"主外键关联"。) </span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">正因为如此：所以Hibernate&#8220;怕&#8221; 在进行 "Class.getStudents().add(stu)" 这样的操作时， <br />出现意外情况(如: stu.getClass=null，即：stu没有所属班级)，<br />即&#8220;添加方&#8221;(Student)与&#8220;被添加方&#8221;(Class)，存在&#8220;外键&#8221;不一致的情况发生。 <br />所以就出现了 那条多余的update语句。即：one-to-many（Class端）主动去维护Child.Class_id <br />所以就是说，Hibernate怕出错，就给你多执行一次无用的更新语句，以保证 add 到 Class&#8220;集合&#8221;中的所有Student<br />都是要与Class有外键关联的。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">用普通话说就是:<br />一年1班.getStudents().add(小白兔);<br />一年1班.getStudents().add(大白兔);</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">也就是说现在不管是 小白兔 还是 大白兔 <br />如果他们，目前还没有自己的班级的话，<br />一年1班的班主任就会主动邀请他们成为一年1班的同学啦~。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">也就是说 一年1班的班主任 主动邀请 同学，而不是 同学自己来~~~ 所以效率也降低了。。。。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">所以我们一般把 一对多端 invser设置为true，即：不让主控端去维护主键关联，<br />（即：让同学自己去找班级）<br />说白了，就是，one-to-many端不用去管理 &#8220;新添加对象&#8221; 的主外键约束问题。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">把one-to-many端（即:class端)的invser设置为true<br />(即：每次向class.getStudents这个集合中添加 student时，不去主动update对应的外键)，<br />而是在student端去手动设置<br />例如：<br />student.setClass(class);<br />session.save(student);<br />这样手动设置 student与class关联啦。。。。<br />所以上面的程序&#8220;最好&#8221;还是写成这样：</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">Class class = new Class();<br />class.setName("一年级1班");<br />session.save(class);</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">Student stu = new Student();<br />stu.setName("小白兔");<br />stu.setClass(class);<br />session.save(class);</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">/*<br />此时向class集合add内容，不会进行数据库操作(update)。<br />&#8220;更新&#8221;的只是session缓存中，数据镜像。<br />这样做的好处是：不仅减少了update语句，<br />而且，同时也更新了session缓存。<br />------------------------<br />而在原来:<br />one-to-many端inverse=false时，虽然也更新seesion缓存中的class集合，<br />但是有却又多余update<br />*/<br />class.getStudents().add(stu);<br />// 提交</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">总结:<br />当inverse=false 并且向one-to-many端的关联集合，添加&#8220;新对象(即: 自由态对象)&#8221; 时，<br />Hibernate就会自动，去update那&#8220;个刚刚到来的&#8221; &#8220;自由态对象&#8221;的外键。<br />（如果你向，one-to-many端添的集合中，add一个&#8220;已经持久化了的对象&#8221;，那就不会出现update了(因为已经持久化过了)，除非，你去 更改&#8220;那个持久化对象&#8221;所对应的外键。。。那样的话。。。呵呵呵~~~<br />你可以试一试，应该不会报错，你可以当做练习去做一下，加深cascade和inverse这两个属性的理解）</span></span></span></span></span></span></p>
<p><br /><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">// 如果看懂了上面的内容。来看一下，下面的东西。<br />假如，将one-to-many端(即:Class端)的 hbm.xml 文档中的cascade移除掉 或把cascade="none"。<br />那么上面的代码会出现什么情况呢。<br />结果会出现2条HQL，和一堆Exception</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年级1班)<br />update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888<br />Hibernate Exceptinon...................................... </span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">相比较cascade被设置"save-update"的时候，缺少了1条 insert语句，而且也多了一些Exception。</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">那么，到底是少了哪1条insert语句呢？<br />就是这条：<br />insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔, 66666666666666666666666666666666)</span></span></span></span></span></span></p>
<p><span style="font-size: 14pt"><span style="font-size: 14pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt">之所以会出现，这样的现象，想必您已经早就看出来了。<br />因为，我没有设置Class端的Cascade，所以在save(class)的时候，并没有自动将其所关联的&#8220;自由态对象&#8221;进行持久化操作。<br />然而，又因为 Class端的inverse=false，所以，Class会自动去维持，那个 &#8220;新来的student&#8221; 的外键。<br />所以会出现，没有insert就要update啦。。。。<br />然后在就是Exception了</span></span></span></span></span></span></p></div></div></div></div></span>?<img src ="http://www.blogjava.net/jimingminlovefly/aggbug/377508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jimingminlovefly/" target="_blank">计明敏</a> 2012-05-07 10:15 <a href="http://www.blogjava.net/jimingminlovefly/articles/377508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse从数据库反向生成实体类之Hibernate方式 反向工程</title><link>http://www.blogjava.net/jimingminlovefly/articles/367169.html</link><dc:creator>计明敏</dc:creator><author>计明敏</author><pubDate>Mon, 26 Dec 2011 03:34:00 GMT</pubDate><guid>http://www.blogjava.net/jimingminlovefly/articles/367169.html</guid><wfw:comment>http://www.blogjava.net/jimingminlovefly/comments/367169.html</wfw:comment><comments>http://www.blogjava.net/jimingminlovefly/articles/367169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jimingminlovefly/comments/commentRss/367169.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jimingminlovefly/services/trackbacks/367169.html</trackback:ping><description><![CDATA[<a href="http://blog.csdn.net/rockstar541/article/details/6840114">http://blog.csdn.net/rockstar541/article/details/6840114</a> <img src ="http://www.blogjava.net/jimingminlovefly/aggbug/367169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jimingminlovefly/" target="_blank">计明敏</a> 2011-12-26 11:34 <a href="http://www.blogjava.net/jimingminlovefly/articles/367169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>