- 浏览: 885534 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
Junjing:
非常感谢楼主的分享,受益匪浅!我是一位从业务规划和运营转需求分 ...
我们应当怎样做需求确认:评审与签字确认会 -
kersky:
感谢楼主的辛苦输出,半天看完了整个系列。对于一个转从开发转需求 ...
我们应当怎样做需求确认:评审与签字确认会 -
DEMONU:
必须要顶
谈谈软件开发的那些事儿 之 软件开发的轮回 -
dripstone:
非常感谢楼主,用了大半天的时间,一口气读完了需求分析阶段。好多 ...
我们应当怎样做需求确认:评审与签字确认会 -
Codepoe:
做了一些开发,看了楼主的文章,我深有感触,为自己的做法找到了理 ...
我们应当改变我们的设计习惯
在前面我写了《如何在spring框架中解决多数据源的问题》,通过设计模式中的Decorator模式在spring框架中解决多数据源的问题,得到了许多网友的关注。在与网友探讨该问题的过程中,我发现我的方案并不完善,它只解决了一部分问题。
总结多数据源的问题,其实它需要分为以下三种情况:各个数据源的数据结构不同、各个数据源的数据结构相同、各个数据源的数据结构部分相同又有部分不同。对于第二种情况,各个数据源的数据结构相同,我们使用一个sessionFactory,而在sessionFactory中通过MultiDataSource来动态切换数据源,应当是一个不错的方案,既解决了多个sessionFactory对相同的值对象重复装载对内存的浪费,又使数据源的切换对客户程序透明,简化了代码的实现和对客户程序的影响。但是,对于第一种情况,各个数据源的数据结构不同,运用这样的方案存在潜在风险。
对于各个数据源的数据结构不同的情况,使用一个sessionFactory而在这个sessionFactory中动态切换数据源,可能造成数据访问的张冠李戴。譬如,数据源A有表T而数据源B没有,可能造成客户程序在访问表T的时候却尝试去连接数据源B,因为客户程序访问哪个数据源是在程序运行期间由客户程序决定的,因此这样的错误是很难发现的。也许客户程序的一个不经意的错误就可能造成错误。解决这个问题的方法有两个:一是严格要求客户程序不要写错,这当然是可以做到的,但作为框架设计者,另一个解决方法是在框架中就避免出现这样的情况。因此我祭出了MultiSessionFactory的方案来解决各个数据源的数据结构不同的多数据源问题。
问题的分析
与MultiDataSource的方案一样,MultiSessionFactory同样是在spring框架下调用ApplicationContext的getBean()方法而不会另外创建beanFacoty,也同样使用Decorator模式来处理切换的问题。MultiSessionFactory的对象关系如图:
在该方案中,SessionFactory就是Hibernate的org.hibernate.SessionFactory接口,Decorator就是MultiSessionFactory,SessionFactory1和SessionFactory2往往是spring的org.springframework.orm.hibernate3.LocalSessionFactoryBean。细心的朋友可能会注意,实际上LocalSessionFactoryBean并不是SessionFactory的实现,这个方案是否有问题呢?这个问题其实也一直困扰了我好久,最后我发现,我们通过ApplicationContext的getBean()得到一个LocalSessionFactoryBean的时候其实并不是真正地得到了它,而是得到了一个SessionFactory,因为spring为LocalSessionFactoryBean重写了getObject(),使其返回的是SessionFactory。一个简单的明证就是,HibernateDaoSupport的sessionFactory属性的类型是SessionFactory,而我们在spring配置的时候注入的却是LocalSessionFactoryBean。
在整个这个方案中,我们需要实现的只有MultiSessionFactory类和我们可爱的Spserver,总共就两个类,然后呢就是一些spring的配置,就完成了。 MultiSessionFactory实现了SessionFactory,同时为了得到AplicationContext而实现了ApplicationContextAware。MultiSessionFactory的代码如下: java 代码
MultiSessionFactory的完整代码见我提供的附件。setSessionFactory()实际上是设定的默认sessionFactory,它在spring装载的时候调用,其对应的数据源应当是主数据源,即项目初始化中需要读取初始化数据的数据源。在任何多数据源项目中,都应当有一个存放初始化数据、系统维护数据、用户权限数据的数据源,这就是主数据源。因此MultiSessionFactory的配置应当这样写: xml 代码
方案的实现
SpServer的写法与《如何在spring框架中解决多数据源的问题》中的一样,我就不再累赘了。
另外,在spring配置中配置多个数据源,每个数据源对应一个sessionFactory,这个对应的sessionFactory中的值对象应当是该数据源的值对象。客户程序在执行数据访问前,通过调用SpServer的putSp()方法,告诉MultiSessionFactory需要切换到哪个sessionFactory,然后执行数据访问。这样,不同数据源的值对象通过放在不同的sessionFactory中,避免了张冠李戴的情况。具体的示例见附件的MultiSessionFactoryTest。
另外的方案
也许有些朋友对以上方案还不满意,因为在执行数据访问前毕竟还要多做一步指定sessionFactory的工作。实际上,对于各个数据源的数据结构不同的项目,一个值对象应当使用哪个数据源有一个非常确定的对应关系。如果通过配置文件将值对象与它的sessionFactory对应起来,那么我们在执行数据访问的时候传递的是哪个值对象,MultiSessionFactory马上就可以去找到对应的sessionFactory。这个方案你可以通过AOP来制作一个拦截器拦截所有诸如save()、delete()、get()、load()等方法来实现,也可以扩展HibernateDaoSupport来实现。这样的方案使客户程序甚至都不用知道他是在操作的一个多数据源系统。当然,这个方案感兴趣的朋友可以自己去实现。
另外,在这个方案中的核心是运用Decorator设计模式来解决切换sessionFactory的目的,即MultiSessionFactory的实现。至于通过什么方式来通知MultiSessionFactory应当切换到哪个SessionFactory,可以根据不同项目的情况自由选择。我在这里给大家提供了通过SpOberver和建立值对象与sessionFactory关系的配置文件这两个方案,你也可以有自己的方案解决。
第三种情况的解决方案
前面我已经给出了第一种和第二种情况的解决方案:各个数据源的数据结构不同的情况用MultiSessionFactory解决;各个数据源的数据结构相同的情况用MultiDataSource解决。那么第三种情况,各个数据源的数据结构部分相同又有部分不同,又应当如何解决呢?当然是将MultiSessionFactory和MultiDataSource结合起来解决。对于数据结构不同的部分,其分别创建各自的sessionFactory然后通过MultiSessionFactory来切换,而对于数据结构相同的部分,建立共同的sessionFactory和多个不同的dataSource然后通过MultiDataSource来切换就可以了。
还有的朋友问到这样的方案其事务处理和二级缓存的情况。这个方案是在spring框架下的解决方案,其事务处理的能力也是由spring的能力来决定的。目前spring要处理跨数据库的事务处理是通过JTA来实现的,这种方式在该方案中同样可以实现,朋友们可以试一试。另外,本方案能使用二级缓存吗?当然可以。对于MultiSessionFactory当然没有任何问题,它通过不同的sessionFactory分离开了不同的数据源和值对象,我们可以毫无顾忌地使用。对于MultiDataSource来说,就有点问题了。MultiDataSource使多个数据源使用共同的sessionFactory,因此它仿佛就是将多个数据源在逻辑上合并为一个数据源。正因为如此,我们需要保证对于同一个表在所有数据源中都要主键唯一。什么意思呢?数据源A和数据源B都有表T,如果数据源A中的表T拥有ID为001的一条数据,那么在数据源B的表T中就不能有ID为001的记录。如果你总是通过MultiDataSource来执行表的插入操作,并且使用uuid.hex生成主键,这当然不会有问题。但如果你有通过其它方式插入表的操作,你应当保证这样的唯一性。另外,对于查询的操作,缓存中存放的既可能是数据源A的数据,也可能是数据源B的数据,因此你应当对数据有一个规划。对于表T的数据,哪些应当插入到数据源A中,哪些应当插入到B中,应当有一个定义。假如是通过不同单位来决定插入哪个数据源,那么在查询数据源A的表T是,应当增加条件只查询数据源A应当有的单位而排除调其它单位。如此这样,你只要注意到这两个问题,你就可以放心大胆地使用二级缓存。
评论
<div class='quote_div'><span style=''>在前面我写了《<a href='../../../blog/72486'>如何在</a></span><span><a>spring</a></span><span style=''><a>框架中解决多数据源的问题</a>》,通过设计模式中的</span><span>Decorator</span><span style=''>模式在</span><span>spring</span><span style=''>框架中解决多数据源的问题,得到了许多网友的关注。在与网友探讨该问题的过程中,我发现我的方案并不完善,它只解决了一部分问题。</span>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>总结多数据源的问题,其实它需要分为以下三种情况:各个数据源的数据结构不同、各个数据源的数据结构相同、各个数据源的数据结构部分相同又有部分不同。对于第二种情况,各个数据源的数据结构相同,我们使用一个</span><span>sessionFactory</span><span style=''>,而在</span><span>sessionFactory</span><span style=''>中通过</span><span>MultiDataSource</span><span style=''>来动态切换数据源,应当是一个不错的方案,既解决了多个</span><span>sessionFactory</span><span style=''>对相同的值对象重复装载对内存的浪费,又使数据源的切换对客户程序透明,简化了代码的实现和对客户程序的影响。但是,对于第一种情况,各个数据源的数据结构不同,运用这样的方案存在潜在风险。</span></p>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>对于各个数据源的数据结构不同的情况,使用一个</span><span>sessionFactory</span><span style=''>而在这个</span><span>sessionFactory</span><span style=''>中动态切换数据源,可能造成数据访问的张冠李戴。譬如,数据源</span><span>A</span><span style=''>有表</span><span>T</span><span style=''>而数据源</span><span>B</span><span style=''>没有,可能造成客户程序在访问表</span><span>T</span><span style=''>的时候却尝试去连接数据源</span><span>B</span><span style=''>,因为客户程序访问哪个数据源是在程序运行期间由客户程序决定的,因此这样的错误是很难发现的。也许客户程序的一个不经意的错误就可能造成错误。解决这个问题的方法有两个:一是严格要求客户程序不要写错,这当然是可以做到的,但作为框架设计者,另一个解决方法是在框架中就避免出现这样的情况。因此我祭出了</span><span>MultiSessionFactory</span><span style=''>的方案来解决各个数据源的数据结构不同的多数据源问题。</span></p>
<h2><span style=''>问题的分析</span></h2>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>与</span><span>MultiDataSource</span><span style=''>的方案一样,</span><span>MultiSessionFactory</span><span style=''>同样是在</span><span>spring</span><span style=''>框架下调用</span><span>ApplicationContext</span><span style=''>的</span><span>getBean()</span><span style=''>方法而不会另外创建</span><span>beanFacoty</span><span style=''>,也同样使用</span><span>Decorator</span><span style=''>模式来处理切换的问题。</span><span>MultiSessionFactory</span><span style=''>的对象关系如图:</span></p>
<p class='MsoNormal' style='text-indent: 26.25pt;'> </p>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''><img src='../../../upload/picture/pic/3974/10f6052e-a238-46fd-b6d3-b62321b2c51d.jpg' height='387' alt='' width='563'/></span></p>
<span style=''>在该方案中,</span><span>SessionFactory</span><span style=''>就是</span><span>Hibernate</span><span style=''>的</span><span style='font-size: 10pt; font-family: 'Courier New'; color: black;'>org.hibernate.SessionFactory</span><span style=''>接口,</span><span>Decorator</span><span style=''>就是</span><span>MultiSessionFactory</span><span style=''>,</span><span>SessionFactory1</span><span style=''>和</span><span>SessionFactory2</span><span style=''>往往是</span><span>spring</span><span style=''>的</span><span style='font-size: 10pt; font-family: 'Courier New';'>org.springframework.orm.hibernate3.LocalSessionFactoryBean</span><span style=''>。细心的朋友可能会注意,实际上</span><span style='font-size: 10pt; font-family: 'Courier New';'>LocalSessionFactoryBean</span><span style=''>并不是</span><span>SessionFactory</span><span style=''>的实现,这个方案是否有问题呢?这个问题其实也一直困扰了我好久,最后我发现,我们通过</span><span>ApplicationContext</span><span style=''>的</span><span>getBean()</span><span style=''>得到一个</span><span style='font-size: 10pt; font-family: 'Courier New';'>LocalSessionFactoryBean</span><span style=''>的时候其实并不是真正地得到了它,而是得到了一个</span><span>SessionFactory</span><span style=''>,因为</span><span>spring</span><span style=''>为</span><span style='font-size: 10pt; font-family: 'Courier New';'>LocalSessionFactoryBean</span><span style=''>重写了</span><span>getObject()</span><span style=''>,使其返回的是</span><span>SessionFactory</span><span style=''>。一个简单的明证就是,</span><span>HibernateDaoSupport</span><span style=''>的</span><span>sessionFactory</span><span style=''>属性的类型是</span><span>SessionFactory</span><span style=''>,而我们在</span><span>spring</span><span style=''>配置的时候注入的却是</span><span style='font-size: 10pt; font-family: 'Courier New';'>LocalSessionFactoryBean</span><span style=''>。</span>
<h2><span style=''>方案的实现</span></h2>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>在整个这个方案中,我们需要实现的只有</span><span>MultiSessionFactory</span><span style=''>类和我们可爱的</span><span>Spserver</span><span style=''>,总共就两个类,然后呢就是一些</span><span>spring</span><span style=''>的配置,就完成了。</span></p>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span>MultiSessionFactory</span><span style=''>实现了</span><span>SessionFactory</span><span style=''>,同时为了得到</span><span>AplicationContext</span><span style=''>而实现了</span><span style='font-size: 10pt; font-family: 'Courier New'; color: black;'>ApplicationContextAware</span><span style=''>。</span><span>MultiSessionFactory</span><span style=''>的代码如下:</span></p>
<div class='code_title'>java 代码</div>
<span>
<div class='dp-highlighter'><ol class='dp-j'>
<li class='alt'><span><span class='keyword'>public</span><span> </span><span class='keyword'>class</span><span> MultiSessionFactory </span><span class='keyword'>implements</span><span> SessionFactory, ApplicationContextAware { </span></span> </li>
<li><span> </span><span class='keyword'>private</span><span> </span><span class='keyword'>static</span><span> </span><span class='keyword'>final</span><span> </span><span class='keyword'>long</span><span> serialVersionUID = 2064557324203496378L; </span> </li>
<li class='alt'><span> </span><span class='keyword'>private</span><span> </span><span class='keyword'>static</span><span> </span><span class='keyword'>final</span><span> Log log = LogFactory.getLog(MultiSessionFactory.</span><span class='keyword'>class</span><span>); </span> </li>
<li><span> </span><span class='keyword'>private</span><span> ApplicationContext applicationContext = </span><span class='keyword'>null</span><span>; </span> </li>
<li class='alt'><span> </span><span class='keyword'>private</span><span> SessionFactory sessionFactory = </span><span class='keyword'>null</span><span>; </span> </li>
<li><span> </span><span class='keyword'>public</span><span> ApplicationContext getApplicationContext() { </span> </li>
<li class='alt'><span> </span><span class='keyword'>return</span><span> applicationContext; </span> </li>
<li><span> } </span> </li>
<li class='alt'><span> </span><span class='keyword'>public</span><span> </span><span class='keyword'>void</span><span> setApplicationContext(ApplicationContext applicationContext) { </span> </li>
<li><span> </span><span class='keyword'>this</span><span>.applicationContext = applicationContext; </span> </li>
<li class='alt'><span> } </span> </li>
<li><span> </span><span class='keyword'>public</span><span> SessionFactory getSessionFactory(String sessionFactoryName) { </span> </li>
<li class='alt'><span> log.debug(</span><span class='string'>"sessionFactoryName:"</span><span>+sessionFactoryName); </span> </li>
<li><span> </span><span class='keyword'>try</span><span>{ </span> </li>
<li class='alt'><span> </span><span class='keyword'>if</span><span>(sessionFactoryName==</span><span class='keyword'>null</span><span>||sessionFactoryName.equals(</span><span class='string'>""</span><span>)){ </span> </li>
<li><span> </span><span class='keyword'>return</span><span> sessionFactory; </span> </li>
<li class='alt'><span> } </span> </li>
<li><span> </span><span class='keyword'>return</span><span> (SessionFactory)</span><span class='keyword'>this</span><span>.getApplicationContext().getBean(sessionFactoryName); </span> </li>
<li class='alt'><span> }</span><span class='keyword'>catch</span><span>(NoSuchBeanDefinitionException ex){ </span> </li>
<li><span> </span><span class='keyword'>throw</span><span> </span><span class='keyword'>new</span><span> DaoException(</span><span class='string'>"There is not the sessionFactory </span> </li>
<li class='alt'><span> } </span> </li>
<li><span> } </span> </li>
<li class='alt'><span> </span> </li>
<li><span> </span><span class='keyword'>public</span><span> SessionFactory getSessionFactory() { </span> </li>
<li class='alt'><span> String sessionFactoryName = SpObserver.getSp(); </span> </li>
<li><span> </span><span class='keyword'>return</span><span> getSessionFactory(sessionFactoryName); </span> </li>
<li class='alt'><span> } </span> </li>
<li><span> </span> </li>
<li class='alt'><span> </span><span class='keyword'>public</span><span> </span><span class='keyword'>void</span><span> setSessionFactory(SessionFactory sessionFactory) { </span> </li>
<li><span> </span><span class='keyword'>this</span><span>.sessionFactory = sessionFactory; </span> </li>
<li class='alt'><span> } </span> </li>
<li><span> </span> </li>
<li class='alt'><span> </span><span class='comment'>// SessionFactory接口需要实现的方法 </span><span> </span> </li>
<li><span> </span> </li>
<li class='alt'><span>...... </span> </li>
<li><span> </span> </li>
<li class='alt'><span>} </span> </li>
</ol></div>
<p class='MsoNormal' style='text-indent: 26.25pt;'>MultiSessionFactory<span style=''>的完整代码见我提供的附件。</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>setSessionFactory()</span><span style=''>实际上是设定的默认</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>sessionFactory</span><span style=''>,它在</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>spring</span><span style=''>装载的时候调用,其对应的数据源应当是主数据源,即项目初始化中需要读取初始化数据的数据源。在任何多数据源项目中,都应当有一个存放初始化数据、系统维护数据、用户权限数据的数据源,这就是主数据源。因此</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>MultiSessionFactory</span><span style=''>的配置应当这样写:</span></p>
<span>
<div class='code_title'>xml 代码</div>
</span><span>
<div class='dp-highlighter'><ol class='dp-xml'>
<li class='alt'><span><span class='tag'><</span><span class='tag-name'>bean</span><span> </span><span class='attribute'>id</span><span>=</span><span class='attribute-value'>"sessionFactory"</span><span> </span><span class='attribute'>class</span><span>=</span><span class='attribute-value'>"com.htxx.service.dao.MultiSessionFactory"</span><span class='tag'>></span><span> </span></span> </li>
<li><span> </span><span class='tag'><</span><span class='tag-name'>property</span><span> </span><span class='attribute'>name</span><span>=</span><span class='attribute-value'>"sessionFactory"</span><span class='tag'>></span><span class='tag'><</span><span class='tag-name'>ref</span><span> </span><span class='attribute'>bean</span><span>=</span><span class='attribute-value'>"hostSessionFactory"</span><span class='tag'>/><span class='tag'><span class='tag-name'>property</span><span class='tag'>></span><span> </span></span> </span></li>
<li class='alt'><span class='tag'><span class='tag-name'><span class='tag'>></span><span> </span></span> </span></li>
</ol></div>
<p class='MsoNormal' style='text-indent: 26.25pt;'>SpServer<span style=''>的写法与<a href='../../../blog/72486'>《如何在</a></span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'><a>spring</a></span><span style=''><a>框架中解决多数据源的问题》</a>中的一样,我就不再累赘了。</span></p>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>另外,在</span><span>spring</span><span style=''>配置中配置多个数据源,每个数据源对应一个</span><span>sessionFactory</span><span style=''>,这个对应的</span><span>sessionFactory</span><span style=''>中的值对象应当是该数据源的值对象。客户程序在执行数据访问前,通过调用</span><span>SpServer</span><span style=''>的</span><span>putSp()</span><span style=''>方法,告诉</span><span>MultiSessionFactory</span><span style=''>需要切换到哪个</span><span>sessionFactory</span><span style=''>,然后执行数据访问。这样,不同数据源的值对象通过放在不同的</span><span>sessionFactory</span><span style=''>中,避免了张冠李戴的情况。具体的示例见附件的</span><span>MultiSessionFactoryTest</span><span style=''>。</span></p>
<h2><span style=''>另外的方案</span></h2>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>也许有些朋友对以上方案还不满意,因为在执行数据访问前毕竟还要多做一步指定</span><span>sessionFactory</span><span style=''>的工作。实际上,对于各个数据源的数据结构不同的项目,一个值对象应当使用哪个数据源有一个非常确定的对应关系。如果通过配置文件将值对象与它的</span><span>sessionFactory</span><span style=''>对应起来,那么我们在执行数据访问的时候传递的是哪个值对象,</span><span>MultiSessionFactory</span><span style=''>马上就可以去找到对应的</span><span>sessionFactory</span><span style=''>。这个方案你可以通过</span><span>AOP</span><span style=''>来制作一个拦截器拦截所有诸如</span><span>save()</span><span style=''>、</span><span>delete()</span><span style=''>、</span><span>get()</span><span style=''>、</span><span>load()</span><span style=''>等方法来实现,也可以扩展</span><span>HibernateDaoSupport</span><span style=''>来实现。这样的方案使客户程序甚至都不用知道他是在操作的一个多数据源系统。当然,这个方案感兴趣的朋友可以自己去实现。</span></p>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>另外,在这个方案中的核心是运用</span><span>Decorator</span><span style=''>设计模式来解决切换</span><span>sessionFactory</span><span style=''>的目的,即</span><span>MultiSessionFactory</span><span style=''>的实现。至于通过什么方式来通知</span><span>MultiSessionFactory</span><span style=''>应当切换到哪个</span><span>SessionFactory</span><span style=''>,可以根据不同项目的情况自由选择。我在这里给大家提供了通过</span><span>SpOberver</span><span style=''>和建立值对象与</span><span>sessionFactory</span><span style=''>关系的配置文件这两个方案,你也可以有自己的方案解决。</span></p>
<h2><span style=''>第三种情况的解决方案</span></h2>
<p class='MsoNormal' style='text-indent: 26.25pt;'><span style=''>前面我已经给出了第一种和第二种情况的解决方案:各个数据源的数据结构不同的情况用</span><span>MultiSessionFactory</span><span style=''>解决;各个数据源的数据结构相同的情况用</span><span>MultiDataSource</span><span style=''>解决。那么第三种情况,各个数据源的数据结构部分相同又有部分不同,又应当如何解决呢?当然是将</span><span>MultiSessionFactory</span><span style=''>和</span><span>MultiDataSource</span><span style=''>结合起来解决。对于数据结构不同的部分,其分别创建各自的</span><span>sessionFactory</span><span style=''>然后通过</span><span>MultiSessionFactory</span><span style=''>来切换,而对于数据结构相同的部分,建立共同的</span><span>sessionFactory</span><span style=''>和多个不同的</span><span>dataSource</span><span style=''>然后通过</span><span>MultiDataSource</span><span style=''>来切换就可以了。</span></p>
<span style=''>还有的朋友问到这样的方案其事务处理和二级缓存的情况。这个方案是在</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>spring</span><span style=''>框架下的解决方案,其事务处理的能力也是由</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>spring</span><span style=''>的能力来决定的。目前</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>spring</span><span style=''>要处理跨数据库的事务处理是通过</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>JTA</span><span style=''>来实现的,这种方式在该方案中同样可以实现,朋友们可以试一试。另外,本方案能使用二级缓存吗?当然可以。对于</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>MultiSessionFactory</span><span style=''>当然没有任何问题,它通过不同的</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>sessionFactory</span><span style=''>分离开了不同的数据源和值对象,我们可以毫无顾忌地使用。对于</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>MultiDataSource</span><span style=''>来说,就有点问题了。</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>MultiDataSource</span><span style=''>使多个数据源使用共同的</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>sessionFactory</span><span style=''>,因此它仿佛就是将多个数据源在逻辑上合并为一个数据源。正因为如此,我们需要保证对于同一个表在所有数据源中都要主键唯一。什么意思呢?数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>A</span><span style=''>和数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>B</span><span style=''>都有表</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>T</span><span style=''>,如果数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>A</span><span style=''>中的表</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>T</span><span style=''>拥有</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>ID</span><span style=''>为</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>001</span><span style=''>的一条数据,那么在数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>B</span><span style=''>的表</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>T</span><span style=''>中就不能有</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>ID</span><span style=''>为</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>001</span><span style=''>的记录。如果你总是通过</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>MultiDataSource</span><span style=''>来执行表的插入操作,并且使用uuid.hex生成主键,这当然不会有问题。但如果你有通过其它方式插入表的操作,你应当保证这样的唯一性。另外,对于查询的操作,缓存中存放的既可能是数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>A</span><span style=''>的数据,也可能是数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>B</span><span style=''>的数据,因此你应当对数据有一个规划。对于表</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>T</span><span style=''>的数据,哪些应当插入到数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>A</span><span style=''>中,哪些应当插入到</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>B</span><span style=''>中,应当有一个定义。假如是通过不同单位来决定插入哪个数据源,那么在查询数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>A</span><span style=''>的表</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>T</span><span style=''>是,应当增加条件只查询数据源</span><span style='font-size: 10.5pt; font-family: 'Times New Roman';'>A</span><span style=''>应当有的单位而排除调其它单位。如此这样,你只要注意到这两个问题,你就可以放心大胆地使用二级缓存。</span></span></span></div>
<p> </p>
http://www.iteye.com/post/411231
我是用的这个驱动com.microsoft.sqlserver.jdbc.SQLServerDriver,很稳定没有发现什么问题,你可以在微软发布的sqljdbc.jar中找到。
我用的jtds驱动,不过我估计多半是hibernate的问题,跟驱动没太多关系。因为同样的驱动,在去掉hibernate改为jdbc连接数据库以后问题马上消失。
http://www.iteye.com/post/411231
我是用的这个驱动com.microsoft.sqlserver.jdbc.SQLServerDriver,很稳定没有发现什么问题,你可以在微软发布的sqljdbc.jar中找到。
http://www.iteye.com/post/411231
如果我是用oracle,但我只有一个数据源,我现在建了多个schema,那能否动态改变sessionFactory中的default_schema设置,来指向特定的schema查询,如果可以,怎么改变,好象无法改变LocalSessionFactoryBean,因为这是spring代理过了?
首先在spring里为每一个schema配置一个dataSource,然后像我的博客写的那样,配置一个multiDataSource,将sessionFactory指向multiDataSource,spring的配置工作就完成了。剩下的工作就是在用户登录的时候,告诉系统他应当访问那个数据源(如同博客上说的那样设计,你也可以自己设计其它的方式,总之告诉系统他访问的数据源)。
其实一直以来我都有一个误解,后来经过一番仔细研究以后才发现弄明白,那就是,在hibernate中的事务处理与session以及sessionFactory没有直接的关联。hibernate使用session进行各种操作,但这些操作只是模拟地进行数据库操作,并没有真正去操作。当它要真正去执行数据库操作的时候,它实际上是将这些操作交给hibernate的事务处理部分进行处理。因此,在我的方案中为你提供了多数据源处理,而其事务处理只与你配置的事务处理方式有关。你这里的操作是跨数据库的事务处理,应当使用JTA事务处理方式。这方面的配置你可以在网上搜寻相关文档。
可能太忙了吧?当上准爸爸了,恭喜恭喜先!
发表评论
-
现在我们在hibernate中还需要使用多表查询吗?
2007-10-08 12:20 12168最近我和一朋友讨论如何在在spring+hibernate框架 ... -
如何在spring框架中解决多数据源的问题
2007-04-19 16:08 46382在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库, ... -
回复:《如何在struts+spring+hibernate的框架下构建低耦合高内聚的软件》
2007-02-07 10:18 6291前几天我写了《如何在struts+spring+hib ... -
如何在struts+spring+hibernate的框架下构建低耦合高内聚的软件
2007-01-16 11:04 24355一.问题的提出 我常常 ...
相关推荐
在纷析云开源财务系统中,Vue3可能被用于构建用户界面,提供直观的交互体验和灵活的数据绑定,确保用户能够轻松操作和管理财务数据。 开源云财务软件的概念意味着源代码对公众开放,用户可以自由查看、使用、修改和...
此zip压缩包中包含了本毕业设计的全部内容,具体包括源代码、论文以及PPT模板。 配置好java环境就能跑,如需其他功能可自行扩展, 运行条件: 确保已安装JDK 1.8及以上版本,并配置好Java环境变量。 使用Eclipse或...
此zip压缩包中包含了本毕业设计的全部内容,具体包括源代码、论文以及PPT模板。 配置好java环境就能跑,如需其他功能可自行扩展, 运行条件: 确保已安装JDK 1.8及以上版本,并配置好Java环境变量。 使用Eclipse或...
在这个"剖 析 Webwork 源 码_V0.9"的资源包中,我们可以深入理解Webwork的核心机制和设计思想。以下是关于Webwork的一些关键知识点: 1. **MVC架构**: - MVC模式是软件工程中一种用于分离业务逻辑、数据模型与...
13. **Spring框架**:Spring是Java企业级应用的主流框架,它简化了依赖注入、AOP(面向切面编程)、事务管理等多个方面的工作。 14. **Lambda表达式**:Java 8引入的Lambda表达式简化了函数式编程,使得代码更简洁...
- **概念**:多线程是指在单个程序中同时运行多个线程的能力。 - **线程创建**:通过继承`Thread`类或实现`Runnable`接口。 - **线程同步**:使用`synchronized`关键字、`ReentrantLock`等工具进行同步。 - **并发...