spring boot 数据库的java web 想从A数据库读取数据写入B数据库,请帮忙想想怎么处理

在应用层通过spring特性解决数据库读写分离 - 开涛的博客(扫描头像关注笔者公众号,掌握最新技术&架构) - ITeye技术网站
博客分类:
如何配置mysql数据库的主从?
单机配置mysql主从:
常见的解决数据库读写分离有两种方案
目前的一些解决方案需要在程序中手动指定数据源,比较麻烦,后边我会通过AOP思想来解决这个问题。
mysql-proxy:
for MySQL:和
此处我们介绍一种在应用层的解决方案,通过spring动态数据源和AOP来解决数据库的读写分离。
该方案目前已经在一个互联网项目中使用了,而且可以很好的工作。
该方案目前支持
一读多写;当写时默认读操作到写库、当写时强制读操作到读库。
考虑未来支持
读库负载均衡、读库故障转移等。
不想引入中间件,想在应用层解决读写分离,可以考虑这个方案;
建议数据访问层使用jdbc、ibatis,不建议hibernate。
应用层解决,不引入额外中间件;
在应用层支持『当写时默认读操作到写库』,这样如果我们采用这种方案,在写操作后读数据直接从写库拿,不会产生数据复制的延迟问题;
应用层解决读写分离,理论支持任意数据库。
1、不支持@Transactional注解事务,此方案要求所有读方法必须是read-only=true,因此如果是@Transactional,这样就要求在每一个读方法头上加@Transactional 且readOnly属性=true,相当麻烦。 :oops:
2、必须按照配置约定进行配置,不够灵活。
方案1:当只有读操作的时候,直接操作读库(从库);
当在写事务(即写主库)中读时,也是读主库(即参与到主库操作),这样的优势是可以防止写完后可能读不到刚才写的数据;
此方案其实是使用事务传播行为为:SUPPORTS解决的。
方案2:当只有读操作的时候,直接操作读库(从库);
当在写事务(即写主库)中读时,强制走从库,即先暂停写事务,开启读(读从库),然后恢复写事务。
此方案其实是使用事务传播行为为:NOT_SUPPORTS解决的。
mon.datasource.ReadWriteDataSource:读写分离的动态数据源,类似于AbstractRoutingDataSource,具体参考javadoc;
mon.datasource.ReadWriteDataSourceDecision:读写库选择的决策者,具体参考javadoc;
mon.datasource.ReadWriteDataSourceProcessor:此类实现了两个职责(为了减少类的数量将两个功能合并到一起了):读/写动态数据库选择处理器、通过AOP切面实现读/写选择,具体参考javadoc。
1、数据源配置
1.1、写库配置
&bean id="writeDataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource"&
&property name="alias" value="writeDataSource"/&
&property name="driver" value="${write.connection.driver_class}" /&
&property name="driverUrl" value="${write.connection.url}" /&
&property name="user" value="${write.connection.username}" /&
&property name="password" value="${write.connection.password}" /&
&property name="maximumConnectionCount" value="${write.proxool.maximum.connection.count}"/&
&property name="minimumConnectionCount" value="${write.proxool.minimum.connection.count}" /&
&property name="statistics" value="${write.proxool.statistics}" /&
&property name="simultaneousBuildThrottle" value="${write.proxool.simultaneous.build.throttle}"/&
1.2、读库配置
&bean id="readDataSource1" class="org.logicalcobwebs.proxool.ProxoolDataSource"&
&property name="alias" value="readDataSource"/&
&property name="driver" value="${read.connection.driver_class}" /&
&property name="driverUrl" value="${read.connection.url}" /&
&property name="user" value="${read.connection.username}" /&
&property name="password" value="${read.connection.password}" /&
&property name="maximumConnectionCount" value="${read.proxool.maximum.connection.count}"/&
&property name="minimumConnectionCount" value="${read.proxool.minimum.connection.count}" /&
&property name="statistics" value="${read.proxool.statistics}" /&
&property name="simultaneousBuildThrottle" value="${read.proxool.simultaneous.build.throttle}"/&
1.3、读写动态库配置
通过writeDataSource指定写库,通过readDataSourceMap指定从库列表,从库列表默认通过顺序轮询来使用读库,具体参考javadoc;
&bean id="readWriteDataSource" class="mon.datasource.ReadWriteDataSource"&
&property name="writeDataSource" ref="writeDataSource"/&
&property name="readDataSourceMap"&
&entry key="readDataSource1" value-ref="readDataSource1"/&
&entry key="readDataSource2" value-ref="readDataSource1"/&
&entry key="readDataSource3" value-ref="readDataSource1"/&
&entry key="readDataSource4" value-ref="readDataSource1"/&
&/property&
2、XML事务属性配置
所以读方法必须是read-only(必须,以此来判断是否是读方法)。
&tx:advice id="txAdvice" transaction-manager="txManager"&
&tx:attributes&
&tx:method name="save*" propagation="REQUIRED" /&
&tx:method name="add*" propagation="REQUIRED" /&
&tx:method name="create*" propagation="REQUIRED" /&
&tx:method name="insert*" propagation="REQUIRED" /&
&tx:method name="update*" propagation="REQUIRED" /&
&tx:method name="merge*" propagation="REQUIRED" /&
&tx:method name="del*" propagation="REQUIRED" /&
&tx:method name="remove*" propagation="REQUIRED" /&
&tx:method name="put*" read-only="true"/&
&tx:method name="query*" read-only="true"/&
&tx:method name="use*" read-only="true"/&
&tx:method name="get*" read-only="true" /&
&tx:method name="count*" read-only="true" /&
&tx:method name="find*" read-only="true" /&
&tx:method name="list*" read-only="true" /&
&tx:method name="*" propagation="REQUIRED"/&
&/tx:attributes&
&/tx:advice&
3、事务管理器
事务管理器管理的是readWriteDataSource
&bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&
&property name="dataSource" ref="readWriteDataSource"/&
4、读/写动态数据库选择处理器
根据之前的txAdvice配置的事务属性决定是读/写,具体参考javadoc;
forceChoiceReadWhenWrite:用于确定在如果目前是写(即开启了事务),下一步如果是读,是直接参与到写库进行读,还是强制从读库读,具体参考javadoc;
&bean id="readWriteDataSourceTransactionProcessor" class="mon.datasource.ReadWriteDataSourceProcessor"&
&property name="forceChoiceReadWhenWrite" value="false"/&
5、事务切面和读/写库选择切面
&aop:config expose-proxy="true"&
&!-- 只对业务逻辑层实施事务 --&
&aop:pointcut id="txPointcut" expression="execution(* cn.javass..service..*.*(..))" /&
&aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/&
&!-- 通过AOP切面实现读/写库选择 --&
&aop:aspect order="-" ref="readWriteDataSourceTransactionProcessor"&
&aop:around pointcut-ref="txPointcut" method="determineReadOrWriteDB"/&
&/aop:aspect&
&/aop:config&
1、事务切面一般横切业务逻辑层;
2、此处我们使用readWriteDataSourceTransactionProcessor的通过AOP切面实现读/写库选择功能,order=Integer.MIN_VALUE(即最高的优先级),从而保证在操作事务之前已经决定了使用读/写库。
6、测试用例
只要配置好事务属性(通过read-only=true指定读方法)即可,其他选择读/写库的操作都交给readWriteDataSourceTransactionProcessor完成。
可以参考附件的:
cn.javass.readwrite.ReadWriteDBTestWithForceChoiceReadOnWriteFalse
cn.javass.readwrite.ReadWriteDBTestWithNoForceChoiceReadOnWriteTrue
可以下载附件的代码进行测试,具体选择主/从可以参考日志输出。
暂不想支持@Transactional注解式事务。
PS:欢迎拍砖指正。
下载次数: 2290
浏览 40767
我在使用BeanPostProcessor拦截NameMatchTransactionAttributeSource的时候,怎么也拦截不到这个类,我想知道有什么可能会造成这样的情况我的也是,永远都不会匹配NameMatchTransactionAttributeSource类型,,然后导致读map永远是{}
楼主的文章写的很好,值得学习。关于sprng配置动态数据源,我这边遇到一个问题.我没有用aop来配置哪些方法连写的库,哪些方法连读的库。我直接是在指定的查询方法里调用ReadWriteDataSourceDecision.markRead()方法,方法执行完之后再调用reset方法。但是这样会有一个问题,用户并发量大时候,就会有数据源错乱,在写数据库操作的方法里会引用到只读的数据库。楼主问题下这是什么情况啊?——估计是WEB服务器都是使用的线程池,有线程变量没清空。
开涛你好,我在使用BeanPostProcessor拦截NameMatchTransactionAttributeSource的时候, 报了如下异常,导致拦截失败。请问有解决办法么19:46:49.865 [localhost-startStop-1] INFO& org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean '(inner bean)#470' of type [class org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)目前确定是与shiro的配置造成的,&bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&&&&&&&& &property name="securityManager" ref="securityManager"/&&&&&&&& &!-- override these for application-specific URLs if you like:--&&&&&&&& &property name="loginUrl" value="${shiro.login.url}"/&&&&&&&& &property name="unauthorizedUrl" value="${shiro.unauthorizedUrl}"/&&&&&&&& &!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean& --&&&&&&&& &!-- defined will be automatically acquired and available via its beanName in chain&&&&&&& --&&&&&&&& &!-- definitions, but you can perform instance overrides or name aliases here if you like: --&&&&&&&& &property name="filters"&&&&&&&&&&&& &util:map&&&&&&&&&&&&&&&& &entry key="authc" value-ref="formAuthenticationFilter"/&&&&&&&&&&&&&&&& &entry key="logout" value-ref="logoutFilter"/&&&&&&&&&&&&&&&& &entry key="sysUser" value-ref="sysUserFilter"/&&&&&&&&&&&&&&&& &entry key="onlineSession" value-ref="onlineSessionFilter"/&&&&&&&&&&&&&&&& &entry key="syncOnlineSession" value-ref="syncOnlineSessionFilter"/&&&&&&&&&&&&&&&& &entry key="jCaptchaValidate" value-ref="jCaptchaValidateFilter"/&&&&&&&&&&&&&&&& &entry key="develop" value-ref="developFilter"/&&&&&&&&&&&& &/util:map&&&&&&&& &/property&&&&&&&& &property name="filterChainDefinitions"&&&&&&&&&&&& &value&&&&&&&&&&&&&&&& /static/** = anon&&&&&&&&&&&&&&& /anon/** = anon&&&&&&&&&&&&&&& /login.json = anon&&&&&&&&&&&&&&& /jcaptcha* = anon&&&&&&&&&&&&&&& /logout = logout&&&&&&&&&&&&&&& /login = jCaptchaValidate,authc&&&&&&&&&&&&&&& /** = develop,sysUser,onlineSession,user,syncOnlineSession,perms,roles&&&&&&&&&&& &/value&&&&&&&& &/property&&&& &/bean&去掉才可以
可以讲讲请问如果有如下的使用情况,该如何解决,管理数据库 manager.db 里面记录每个分公司账册数据库名称Jiangsu.dbHunan.dbZhejiang.dbmanager.db中的分账册数据库名是动态的,并不是一个固定记录,我只定义了指向manager.db的datasource,用于登录是获得各自的数据库名主要是如何动态的产生到各自数据库的数据源,我考虑了两个方法1.通过过滤器+session来实现2.使用aop,在servise的before中+session来实现,这些数据库结构一样 系统登录到管理数据库 根据客户端提交的标识 决定客户端登录的默认数据库是那个 但是我不知道这个时候数据源的数据库该如何切换 数据源不是都被在配置文件中定义死了吗。我用spring框架该如何实现。或者有什么变通的办法 后端数据库是sqlserver. 难道只有在操作时都带上库名. 例如select * from [jiangsu].stock. 查询江苏库存select * from [zhejiang].stock. 查询浙江库存么如果可能可以给我个demo,刚刚上手spring, 谢谢过滤器+ThreadLocal+DynamicDataSource完成:1、通过过滤器根据用户登录信息选择库 存到ThreadLocal2、DynamicDataSource通过ThreadLocal选择库3、退出过滤器时删除ThreadLocalDynamicDataSource可以搜索下,很多例子
自定义一个annotation @ReadOnly,把读方法或写方法上标记上@ReadOnly然后再AOP处理时换成某个读DS,可以避免方法命名约束。。。根本之道还是根据sql解析得到是什么操作。例如淘宝的tddl嗯,这个也想到了,但是我觉得如果读方法太多很多的方法头上都有@ReadOnly,不爽 。引用根本之道还是根据sql解析得到是什么操作。例如淘宝的tddl 这个同意,不过如果简单的读写分离用此方案也挺好 ,百合现在用呢。
jinnianshilongnian 写道7454103 写道niceps:在实际项目里面会更关注 自动选择数据源的规则这个也是 Amoeba& 等一些中间建 待完善地方!此方案在一般项目 不想引入中间件可以使用,而且相对来说也不是特别麻烦,几分钟就配置完成了,缺点是不支持@Transactional(不过个人也不喜欢这种风格)Amoeba 有路由规则Amoeba 是有路由规则,就是因为这些规则功能有点弱哈!我们现在的项目也有 读写分离这个功能,没有选择那些中间件,和LZ思路差不多吧!不过,我们是基于注解实现的,定义好几个datasource 由注解选择库,暂时为发现什么缺点!求分享。不过用注解的话 你们对于查怎么做的? 每个查询方法都加?路由的话我也是考虑用注解实现&& 但是好像比较麻烦 对于需要的方法都加注解 量大的话很挠头 不知道你怎么解决的,分享出来吧,周末等待你的文章&& 哈哈哈
7454103 写道nice
ps:在实际项目里面会更关注 自动选择数据源的规则
这个也是 Amoeba& 等一些中间建 待完善地方!
此方案在一般项目 不想引入中间件可以使用,而且相对来说也不是特别麻烦,几分钟就配置完成了,缺点是不支持@Transactional(不过个人也不喜欢这种风格)
Amoeba 有路由规则
Amoeba 是有路由规则,就是因为这些规则功能有点弱哈!
我们现在的项目也有 读写分离这个功能,没有选择那些中间件,和LZ思路差不多吧!
不过,我们是基于注解实现的,定义好几个datasource 由注解选择库,暂时为发现什么缺点!
& 上一页 1
jinnianshilongnian
浏览量:1378037
浏览量:1639406
浏览量:3149306
浏览量:150934
浏览量:830089
浏览量:166008
浏览量:2205424
浏览量:300687
估计pom.xml文件得加这个和修改alibaba的druid ...
@Intercepts({
@Signatur ...
官网英文介绍+楼主资料
但看这一篇博客,完全真不明白,哈哈。。。还是得用到了才好理解啊 ...
本兮挚爱桃子 写道@Value(&#{'Hello' ...&&&&Web服务启动时自动加载Servlet,并读取数据库内容
Web服务启动时自动加载Servlet,并读取数据库内容
重启web容器,在控制台可以看到&test&这么一行信息。
然后我们来修改我们的代码,让这个Servlet可以读取数据库的内容,并进行相关的处理。
我操作数据库用的是spring的HibernateTemplate和JdbcTemplate,访问数据库是以bean注入的方式,在action里注入service的实现,读取数据库数据,其实现在的关键就是得到这个service的实例化对象,
嵌到我的页面
<input type="text" readonly="true" value="">
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
开发技术下载排行Spring访问数据库(oracle)配置
1.spring 对访问的支持
当我们开发持久层的时候,我们面临着多种选择,比如使用JDBC、Hibernate、java持久化API或其它持久化框架。幸好的是spring能够支持所有这些持久化机制。
DAO(data access boject)数据访问对象,这个名字就很形象描述了DAO在应用程序中所扮演的角色。DAO提供了数据的读取、写入到数据库中的一种方式。它们应该以接口的方式发布功能,而应用程序的其它部分就可以通过接口来进行访问了。
注:服务对象本身并不会处理数据访问,而是将数据访问委托给DAO。DAO接口确保其与服务对象的松耦合。
2.配置数据源
spring提供了在spring上下文中配置数据源Bean的多种方式,包括:
a.通过JDBC驱动程序定义的数据源;
b.通过JNDI查找的数据源;
c.连接池的数据源;
接下我们就专门来讲讲从使用连接池获取连接的数据源!(即c点)
上下文配置Bean的代码:
&!--配置数据源 --&
&bean id=&dataSource& class=&mons.dbcp.BasicDataSource&&
&property name=&driverClassName& value=&oracle.jdbc.driver.Driver&/&
&property name=&url& value=&jdbc:oracle:thin:@localhost:1521:orcl&/&
&property name=&username& value=&wwo&/&
&property name=&password& value=&wwo&/&
&!-- 连接池启动时的初始值 --&
&property name=&initialSize& value=&3& /&
&!-- 连接池的最大值 --&
&property name=&maxActive& value=&300& /&
&!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --&
&property name=&maxIdle& value=&2& /&
&!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --&
&property name=&minIdle& value=&1& /&
&!-- end --&
注:JDBC驱动数据源并没有池的概念,因此没有存在池属性的配置!
好了,到这一步,我们已经完成了通过数据源建立了与数据库的连接,接下来就是实际访问数据库了。
3.在Spring中集成Hibernate
Hibernate一些特性:
a.延迟加载(Lazy loading):例如一个Bean对象由其属性及另一个Bean对象组成,如果我们只关注的只是这个Bean对象的属性,那么我们可以借助于延迟加载,只抓取需要的数据;
b.预先抓取(Eager fetching):这与延迟加载是相对的,一个Bean所关联的其它Bean都会被查询出来,这就节省了多次查询的成本;
c.级联(Cascading):有时候删除一个Bean对象后,也希望其同时能数据库中删除掉与其关联的其它Bean。
Spring对Hibernate ORM框架的支持提供了与这些框架集成点以及一些附加的服务,如下所示:
a.Spring声明式事务的集成支持;
b.透明的异常处理;
c.线程安全的、轻量级的模板类;
d.DAO支持类;
e.资源管理。
4.声明会话工厂(Session Factory)
使用Hibernate的主要接口是org.hibernate.Session。Session提供了基本的数据访问功能,如保存、更新、删除以及从数据库加载对象的功能。
能过借助于Hibernate的SessionFactory来获取Session对象,SessionFactory主要负责Hibernate Session的打开、关闭以及管理。
配置在xml上下文的Bean如下:
&bean id=&sessionFactory&
class=&org.springframework.orm.hibernate4.LocalSessionFactoryBean&&
&property name=&dataSource& ref=&dataSource&/&
&property name=&packagesToScan&&
&!--扫描一下实体目录 --&
&value&com.blog.entity&/value&
&/property&
&property name=&hibernateProperties&&
&prop key=&hibernate.dialect&&org.hibernate.dialect.Oracle10gDialect&/prop&
&prop key=&hibernate.show_sql&&true&/prop&
&prop key=&hibernate.format_sql&& true&/prop&
&prop key=&current_session_context_class&&thread&/prop&
&/property&
5.创建自己的基础DAO类
Spring可以通过Spring的Hibernate模板来保证每个事务都使用同一个会话。既然Hibernate能够对其自己进行管理,那就不必要使用模板类了。接下我们直接将Hibernate Session装配到自己的DAO类中。
* @author ckz
* @param &T&
public abstract class BaseDAO&T& {
* 注入sessionFactory
@Autowired
private SessionFactory sessionF
* 获得session
protected Session getCurrentSession() {
return sessionFactory.getCurrentSession();
* @param entity
* @throws Exception
public void add(T entity) throws Exception {
getCurrentSession().save(entity);
* 调用存储过程
* @param proName
public CallableStatement citePro(final String proName){
Session session = getCurrentSession();
CallableStatement proc=session.doReturningWork(
new ReturningWork&CallableStatement&() {
public CallableStatement execute(Connection connection) throws SQLException{
CallableStatement resultSet = connection.prepareCall(proName);
return resultS
* @param entity
* @throws Exception
public void update(T entity) throws Exception {
getCurrentSession().update(entity);
* 保存或更新
* @param entity
* @throws Exception
public void saveOrUpdate(T entity) throws Exception {
getCurrentSession().saveOrUpdate(entity);
* @param entity
* @throws Exception
public void delete(T entity) throws Exception {
getCurrentSession().delete(entity);
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'Spring mvc增删改查怎么把当前时间自动写进数据库_Java Web开发大全_优良自学吧 |
当前位置: >
> Spring mvc增删改查怎么把当前时间自动写进数据库优良自学吧提供Spring mvc增删改查怎么把当前时间自动写进数据库,Spring mvc增删改查如何把当前时间自动写进数据库想把系统时间自动存进SQL&SERVER该怎么处理。建了dates字段,默认值写了getdate(),就是拿不到时间,把java里面的方法去掉SQL里面时间有了,但是页面会报错。 package&nbSpring mvc增删改查如何把当前时间自动写进数据库想把系统时间自动存进SQL&SERVER该怎么处理。建了dates字段,默认值写了getdate(),就是拿不到时间,把java里面的方法去掉SQL里面时间有了,但是页面会报错。
package&com.san.web.
import&javax.persistence.C
import&javax.persistence.E
import&javax.persistence.GeneratedV
import&javax.persistence.GenerationT
import&javax.persistence.Id;
import&javax.persistence.T
@Table(name="hiuser")
public&class&UserInf&{
&&&&&@GeneratedValue(strategy=GenerationType.IDENTITY)
/*主键生成策略*/
@Column(length=32)
private&int&
@Column(length=32)
private&String&userN
@Column(length=32)
private&String&
@Column(length=32)
private&String&
public&int&getNumber()&{
public&void&setNumber(int&number)&{
this.number&=&
public&String&getUserName()&{
return&userN
public&String&getAge()&{
public&String&getDates()&{
public&void&setUserName(String&userName)&{
this.userName&=&userN
public&void&setAge(String&age)&{
this.age&=&
public&void&setDates(String&dates)&{
this.dates&=&
}------解决方案--------------------在基类中各个i增删改查方法中显示调用setDate(new&Date())方法,同时对实体类的setDate(Date&date)方法的修饰改为private禁止别人调用,通常还可以将这个时间戳设置为乐观锁(本文来自互联网,不代表搜站(/)的观点和立场)本站所有内容来自互联网,若本站收录的信息无意侵犯了贵司版权,请给我们来信(),我们会及时处理和回复,谢谢编辑推荐最近更新

我要回帖

更多关于 springlinker数据库 的文章

 

随机推荐