精华内容
下载资源
问答
  • 6.4 SpringBoot中配置数据源

    6.4 SpringBoot中配置多个数据源

    • 就是操作多个数据库所要进行的配置

    第一步:准备2个数据库

    /*
    Navicat MySQL Data Transfer
    
    Source Server         : localhost
    Source Server Version : 80013
    Source Host           : localhost:3306
    Source Database       : test
    
    Target Server Type    : MYSQL
    Target Server Version : 80013
    File Encoding         : 65001
    
    Date: 2020-10-26 21:14:40
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
      `id` int(10) NOT NULL AUTO_INCREMENT,
      `username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
      `password` varchar(20) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES ('1', 'zhangsan', '1234');
    INSERT INTO `user` VALUES ('2', 'lisi', '1234');
    INSERT INTO `user` VALUES ('4', 'shu', '123');
    INSERT INTO `user` VALUES ('5', 'shu1', '123');
    
    
    /*
    Navicat MySQL Data Transfer
    
    Source Server         : localhost
    Source Server Version : 80013
    Source Host           : localhost:3306
    Source Database       : test1
    
    Target Server Type    : MYSQL
    Target Server Version : 80013
    File Encoding         : 65001
    
    Date: 2020-10-26 21:14:50
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for student
    -- ----------------------------
    DROP TABLE IF EXISTS `student`;
    CREATE TABLE `student` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
      `sex` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
    
    -- ----------------------------
    -- Records of student
    -- ----------------------------
    INSERT INTO `student` VALUES ('1', 'shu', '男');
    
    

    在这里插入图片描述

    第二步:pom中添加依赖

    在这里插入图片描述

    <repositories>
        <repository>
          <id>alimaven</id>
          <name>aliyun maven</name>
          <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        </repository>
      </repositories>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
    
      <parent>
        <!--SpringBoot的父依赖-->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
      </parent>
    
      <dependencies>
        <!--SpringBoot配置web依赖-->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入freeMarker的依赖包-->
        <!--<dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>-->
        <!--JDBC-->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--数据库驱动-->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.13</version>
        </dependency>
        <!--单元测试-->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>
        <!--Mybatis-->
        <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>1.1.1</version>
        </dependency>
    
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <build>
        <resources>
          <resource>
            <directory>src/main/java</directory>
            <includes>
              <include>**/*.*</include>
            </includes>
          </resource>
          <resource>
            <directory>src/main/resources</directory>
            <includes>
              <include>**/*.*</include>
            </includes>
          </resource>
        </resources>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    </project>
    

    第三步:application.properties配置文件中添加两个数据源

    在这里插入图片描述

    spring.datasource.test.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
    spring.datasource.test.username=root
    spring.datasource.test.password=root
    spring.datasource.test.driverClassName=com.mysql.cj.jdbc.Driver
    
    spring.datasource.test1.url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC
    spring.datasource.test1.username=root
    spring.datasource.test1.password=root
    spring.datasource.test1.driverClassName=com.mysql.cj.jdbc.Driver
    

    配置多数据源时:
    springboot1.x 版本用url、driverClassName
    springboot2.x 版本用jdbc-url、driver-class-name

    第四步:写2个数据源配置

    • 数据源1
      在这里插入图片描述
    package com.it.datasource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    
    import javax.sql.DataSource;
    
    /**
     * @ClassName DataSource1
     * @Author shuyy
     * @Date 2020/10/26
     **/
    
    @Configuration//注解到springboot容器中
    @MapperScan(basePackages="com.it.test.mapper",sqlSessionFactoryRef="testSqlSessionFactory")
    public class DataSource1 {
    
            /**
             * @return 返回test数据库的数据源
             */
            @Bean(name="testDataSource")
            @Primary//主数据源,一个应用只能配置一个(一山不容二虎),且必须配置,这里不配置报错!
            @ConfigurationProperties(prefix="spring.datasource.test")
            public DataSource dateSource(){
                return DataSourceBuilder.create()//如果失败了可以使用下面这种方法
                        /*.driverClassName("com.mysql.cj.jdbc.Driver")
                        .url("jdbc:mysql://localhost:3306/test?serverTimezone=UTC")
                        .username("root")
                        .password("root")*/
                        .build();
            }
    
            /**
             * @return 返回test数据库的会话工厂
             */
            @Bean(name = "testSqlSessionFactory")
            @Primary
            public SqlSessionFactory sqlSessionFactory(@Qualifier("testDataSource") DataSource ds) throws Exception{
                SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
                bean.setDataSource(ds);
                //这里使用的是注解+接口sql无需配置,如果是xml中写sql,记得配置
                //bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:test/mapper/*.xml"));
                return bean.getObject();
            }
    
            /**
             * @return 返回test数据库的事务
             */
            @Bean(name = "testTransactionManager")
            @Primary
            public DataSourceTransactionManager transactionManager(@Qualifier("testDataSource") DataSource dataSource) {
                return new DataSourceTransactionManager(dataSource);
            }
    
            /**
             * @return 返回test数据库的会话模版
             */
            @Bean(name = "testSqlSessionTemplate")
            @Primary
            public SqlSessionTemplate sqlSessionTemplate(
                    @Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
                return new SqlSessionTemplate(sqlSessionFactory);
            }
        }
    
    
    • 数据源2
      在这里插入图片描述
    package com.it.datasource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    
    import javax.sql.DataSource;
    
    
    @Configuration//注解到springboot容器中
    @MapperScan(basePackages="com.it.test1.mapper",sqlSessionFactoryRef="test1SqlSessionFactory")
    public class DataSource2 {
    
        /**
         * @return 返回test1数据库的数据源
         */
        @Bean(name="test1DataSource")
        @ConfigurationProperties(prefix="spring.datasource.test1")
        public DataSource dateSource(){
            return DataSourceBuilder.create()
                    /*.driverClassName("com.mysql.cj.jdbc.Driver")
                    .url("jdbc:mysql://localhost:3306/test1?serverTimezone=UTC")
                    .username("root")
                    .password("root")*/
                    .build();
        }
    
        /**
         * @return 返回test1数据库的会话工厂
         */
        @Bean(name = "test1SqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("test1DataSource") DataSource ds) throws Exception{
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(ds);
            //bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:test1/mapper/*.xml"));
            return bean.getObject();
        }
    
        /**
         * @return 返回test1数据库的事务
         */
        @Bean(name = "test1TransactionManager")
        public DataSourceTransactionManager transactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        /**
         * @return 返回test1数据库的会话模版
         */
        @Bean(name = "test1SqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(
                @Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }
    
    

    第五步:实体类编写

    • User,【对应数据库字段】为属性提供无参、有参构造、get/set、toString
      在这里插入图片描述
    • Student,为属性提供无参、有参构造、get/set、toString
      在这里插入图片描述

    第六步:test的Mapper&service

    • UserMapper
      在这里插入图片描述
    package com.it.test.mapper;
    
    
    import com.it.test.model.User;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    public interface UserMapper {
    
        @Insert("insert into user(username,password) values(#{username},#{password})")
        void save(@Param("username") String username, @Param("password") String password);
    
        @Select("select * from user where id = #{id}")
        User findUserById(@Param("id") Integer id);
        /*void save(String username,String password);
        User findUserById(Integer id);*/
    }
    
    
    • UserService
      在这里插入图片描述

    • UserServiceImpl
      在这里插入图片描述

    package com.it.test.service.impl;
    
    import com.it.test.mapper.UserMapper;
    import com.it.test.model.User;
    import com.it.test.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * @ClassName UserServiceImpl
     * @Author shuyy
     * @Date 2020/10/26
     **/
    @Service
    @Transactional
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserMapper userMapper;//这里如果报错,正常不影响运行,是springBean扫描所致,它是在运行时自动创建
        /*private JdbcTemplate jdbcTemplate;*///本来这里需要配置数据源,现在在SpringBoot中配置好了无需配置
    
        @Override
        public void register(String username, String password) {
            /*String sql = "insert into user(username,password) values(?,?)";*/
            /*jdbcTemplate.update(sql,username,password);*/
            userMapper.save(username,password);
        }
    
        @Override
        public User findUserById(Integer id) {
            return userMapper.findUserById(id);
        }
    }
    
    

    第七步:test1的Mapper&service

    • StudentMapper
      在这里插入图片描述
    package com.it.test1.mapper;
    
    import com.it.test1.model.Student;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    /**
     * @author ShuYY
     * @date 2020/10/26
     */
    public interface StudentMapper {
    
        @Insert("insert into student(username,sex) values(#{username},#{sex})")
        void save(@Param("username") String username, @Param("sex") String sex);
    
        @Select("select * from student where id = #{id}")
        Student findStuById(@Param("id") Integer id);
    
        /*void save(String username,String sex);
        Student findStuById(Integer id);*/
    }
    
    
    • StudentService
      在这里插入图片描述
    • StudentServiceImpl
      在这里插入图片描述
    package com.it.test1.service.impl;/**
     * @author ShuYangyang
     * @date 2020/10/26 21:46
     */
    
    import com.it.test1.mapper.StudentMapper;
    import com.it.test1.model.Student;
    import com.it.test1.service.StudentService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * @ClassName StudentServiceImpl
     * @Author shuyy
     * @Date 2020/10/26
     **/
    @Service
    @Transactional
    public class StudentServiceImpl implements StudentService {
    
        @Autowired
        private StudentMapper studentMapper;
    
        @Override
        public void save(String username, String sex) {
            studentMapper.save(username,sex);
        }
    
        @Override
        public Student findStuById(Integer id) {
            return studentMapper.findStuById(id);
        }
    }
    
    

    第八步:写个Controller

    • UserController
      在这里插入图片描述
    package com.it.web.controller;
    
    import com.it.test.model.User;
    import com.it.test.service.UserService;
    import com.it.test1.model.Student;
    import com.it.test1.service.StudentService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @ClassName HelloController
     * @Author shuyy
     * @Date 2020/10/25
     **/
    @RestController
    @RequestMapping("user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @Autowired
        private StudentService studentService;
    
        @RequestMapping("register")
        @ResponseBody
        public String register(String username,String password){
            userService.register(username,password);
            studentService.save(username,"男");
            return "success";
        }
    
        @RequestMapping("findUser")
        @ResponseBody
        public User findUser(Integer id){
            return userService.findUserById(id);
        }
    
        @RequestMapping("findStu")
        @ResponseBody
        public Student findStu(Integer id){
            return studentService.findStuById(id);
        }
    
    }
    
    

    第九步:App中

    在这里插入图片描述

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.context.annotation.ComponentScan;
    
    /**
     * @ClassName App
     * @Author shuyy
     * @Date 2020/10/25
     **/
    
    
    @EnableAutoConfiguration/*(exclude={DataSourceAutoConfiguration.class})*///写一个,这里配置了,其它Controller无需写了
    @ComponentScan(basePackages = {"com.it.datasource","com.it.web.controller","com.it.test","com.it.test1"})//配置扫描包
    public class App {
        public static void main(String[] args) {
            SpringApplication.run(App.class,args);
        }
    }
    
    

    效果

    在这里插入图片描述

    6.5 多数据源存在的问题

    1. 修改UserController
      在这里插入图片描述
    2. 修改对应的方法
      在这里插入图片描述
      在这里插入图片描述
    3. 注意这里调换一下方法的顺序!
      在这里插入图片描述
    4. 显然上面这样是不符合事务的要求的,要么全部成功要么全部失败,我们要把它当成一个事务看待处理,就要使用到springboot+jta+atomikos 分布式事务管理来解决这样的现象。(详见下一天)
    展开全文
  • 1、问题背景曾经在某电信SOA项目碰到一个多数据源failover切换问题,其实每月深度巡检SOA套件都发现OSB和SOA环境所使用的数据源存在连接失败或连接超时问题,甚至无法进行failover切换。 OSB和SOA这四个domain采用...

    1、

    问题背景

    曾经在某电信SOA项目碰到一个多数据源failover切换问题,其实每月深度巡检SOA套件都发现OSB和SOA环境所使用的数据源存在连接失败或连接超时问题,甚至无法进行failover切换。 OSB和SOA这四个domain采用的是多数据源配置,一旦其中一个RAC中的节点出现了故障,无法进行failover切换,最后会导致大量流程调用失败,流程因此受阻,直接影响到了日常业务办理。

    系统环境信息:

    操作系统:   HP-UX B.11.31

    JDK版本:  JDK1.7.0.03

    中间件版本:  weblogic10.3.6.0.12

    SOA11.1.1.6.0

    OSB11.1.1.6.0

    集群:是

    2、问题分析过程

    在巡检日志文件中发现大量关于数据源的错误及警告信息,主要分布在

    SOA/OSB

    涉及的四套

    domain

    服务日志文件

    AdminServer.log

    domain

    server

    等日志中。但每天都会频繁产生中间件数据源无法连接

    RAC1

    节点数据库异常问题,客户也反馈业务时常不可用,流程调用失败,影响到了业务。

    以下是

    weblogic

    日志中筛选出来的报错信息:

    2577ec1eced5331666067ba0cc0b49ad.png

    同时也在weblogic控制台监视到了OSB和SOA这几个domain实例的数据源,RAC1对应的数据源存在大量连接失败。可想期间中间件数据源与数据库之间出现断连现象。问题期间存在网络不稳定或是数据库异常问题。最后导致RAC1数据源连接不上数据库节点实例,但连接rac0的数据源连接都正常。后面有向客户提出网络是否稳定?数据库是否异常?当时客户安排了网络工程师和DBA一起来排查问题。网络工程师排查了网络没有出现丢包和网络不稳定问题。DBA排查发现RAC1节点确实有不稳定现象。想想不对啊,虽然数据库不稳定,但我们中间件是多数据源可以实时failover切换啊,为什么不行了。现在抛出数据库问题不管,我们本身中间件的多数据源故障转移机制是否存在问题,针对这种情况我们查了SOA和weblogic很多服务日志和翻阅了很多文档,查到是多数据源的机制出现问题了。

    8553b1f054d51754c5f4a33ebc4ce17e.png

    3

    问题原因

    由于客户的数据库其中某个节点不稳定,而SOA和OSB服务采用多数据源配置,无法进行数据源failover切换。针对WebLogic10.3.4

    后数据源配置官方建议对于RAC

    仅支持

    多数据源/GridLink

    数据源配置,而多数据源是ORACLE 10G RAC以下版本常用的方法,而使用多数据源功能对于容错和负载均衡相对有限。目前应用端使用多数据源来连接ORACLE 11G RAC可能会存在failover局部切换不稳定的问题。因此我们提出建议客户使用GridLink数据源。

    4、优化建议

    1、我们提出让客户将原来的多数据源改造成GridLink数据源,以防数据库RAC节点异常,中间件数据源自动切换正常数据库节点。整个改造过程发了半个月左右,将原来SOA和OSB所用到的多数据源替换成了GridLink数据源,数据库连接地址统一用scan ip和service_name。切换成功后,经过几轮业务高峰期观察,数据库断连问题消除了。以后数据库有异常都能够正常切换,对业务无影响。

    2、解决数据库异常问题。

    通过这次问题我们引入了GridLink组件解决了数据源failover切换问题,接下来简单介绍一下GridLink数据源是一个什么好东西。

    5、GridLink

    数据源介绍

    GridLink

    是WebLogic10.3.4新推出的数据源类型,引入Jdbc 11g version驱动,全面支持Oracle 11G RAC AWM的特性,提供了针对Oracle RAC数据库与WLS之间的连接功能。GridLink通过Oracle通知服务(ONS)来获取OracleRAC实例的状态变化。WLS可以通过Oracle RAC灵活的数据库服务设计来满足其需求,也可以由数据库服务的增加而扩展而不需要关注RAC 集群中的物理结构变化。

    Gridlink

    相对以前的多数据源来说更有效率,因为它很大程度上借助了数据库的功能。它使用了Oracle的ONS(OracleNotification Service)的特征.

    44b42a25aef13ed197d1235bf102f07d.png

    Weblogic10.3.4

    以前的版本是没有这个功能的,请关注下图:

    3b5e6d8747f31c3d96d56f76dbbd4017.png

    6

    、GridLink

    数据源特性

    接下来我们介绍一下GridLink数据源它有哪些特性

    1.简化和统一了对RAC连接配置的模块。

    2.支持Fast Connection Filover(FCF)。

    3.支持Runtime Connection Load Balancing(RCLB)。

    4.支持Single  Client Access Name(SCAN)。

    5.OracleRAC停机的正常处理。

    7aab0cc8e1d187f1ed5fde03515e551c.png

    7

    、GridLink

    数据源优势

    WebLogic 10.3.4

    中,为了增强对RAC的支持,Oracle推出了Gridlink数据源,取代原先的多数据源。原来的多数据源的工作原理是为每台RAC的结点配置一个数据源,然后把所有的这些数据源聚合起来配置一个多数据源。虽然多数据源也提供容错和负载均衡,但是它的功能相对才是有限。

    1

    )

    配置简易

    只需要配置一个Gridlink 数据源,它就会处理与后台的RAC数据库的通讯。相对多数据源管理员的工作量减少很多。

    如果配置了Oracle的SCAN服务就更简单了,RAC结点的添加删除都是自动完成,因为对Gridlink数据源来说,它只知道一个SCAN地址就好了。就好象一个域名一样,你不需要知道后面用了多少IP来实现。而多数据源需要配置多个VIP地址和数据库instnace。

    2)高效容错

    使用ONS,Gridlink数据源可以实时的捕捉到RAC端的信息。如果有数据库节点出错,Gridlink数据源很快将与其对应的连接标识为不可用。

    多数据源需要开启测试连接功能,当应用向一个数据源申请一个连接的时候,WebLogic需要先测试这个连接再返回。如果测试失败,WebLogic会重建一个连接。如果重建再失败,数据源就会被标识成dead,然后WebLogic自动Failover到下一个多数据源里面的数据源。在使用连接中需要不断主动测试连接,保证获取正常可用连接,但是这样会带来的资源开销。

    3)实时负载

    Gridlink 数据源相对来说更有效率,因为它很大程度上借助了数据库的功能。它使用了Oracle的ONS(OracleNotification Service)的特征。Gridlink数据源可以知道哪些RAC节点很忙,哪些很闲,于是它可以有效的将哪些来自空闲RAC的连接分配给应用请求,实现实时负载均衡。

    多数据源如果一个应用开启了多个连接,那么根据轮询的原则,这多个连接可能会来自多个不同的数据库节点。这个实际上有性能上的影响。

    4)沉稳应对RAC节点的关闭

    如果是有计划关闭RAC节点,Gridlink数据源会等当前活动的事务结束再关闭连接。新的连接请求将被发送到其他的RAC节点。

    如果是突发的RAC节点关闭,Gridlink数据源也会沉着的将当前的事务rollback,然后将新的连接请求发送到其他的RAC节点。

    5)全局事务唯一

    Gridlink数据源在一个事务的第一个连接创建后会将该事务的所有后续连接请求发送到同一个RAC节点上。这样可以减少后台同步处理,提高全局事务的运行效率

    多数据源的轮询策略会造成同一个事务的多个连接被发送到不同的RAC节点上。

    8、GridLink

    数据源参考文档

    http://www.oracle.com/technetwork/middleware/weblogic/wls-jdbc-gridlink-howto-333331.html

    有需要的朋友可以关注我的公众号,文章每日一更

    展开全文
  • 前段时间同事在项目当中使用到多数据源,项目集成是mybatis plus ,遇到一个非常神仙BUG,有数据源A ,数据源B,针对数据源A所有操作都没有问题,针对数据源B所有操作,除了批量操作也都没有问题!...

    前段时间同事在项目当中使用到多数据源,项目集成的是mybatis plus ,遇到一个非常神仙的BUG,有数据源A ,数据源B,针对数据源A的所有操作都没有问题,针对数据源B的所有操作,除了批量的操作也都没有问题!!!

    当进行批量操作的时候,发现会提示,xxx表不存在!!!,但是如果是查询数据,不批量进行操作,就可以查询出来,所以当遇到这个神仙BUG的时候,直接蒙圈了!!!

    最后进行到处尝试,分析源码,等待各种方式,搞了一两天,终于知道原因了,mybatis plus里面的批量操作都没有走DAO层,是通过SqlSession进行的,然后数据源的切换是在DAO进行的。

    分析到上面,本以为找到了问题,发现数据源的切换是手写的一个注解,这个注解在其他项目当中是完全没有出现这个问题的!!!最后一步一步跟踪代码分析发现主要原因是在项目配置多数据源的时候,会指定每个数据源的DAO层接口位置。然后将DAO接口位置和数据源的关系存储起来,然后调用DAO层的时候就调用对应的数据源。但是在这个项目当中,DAO层没有分包,两个数据源指定的DAO层位置都一样,就导致出现这个问题。

    最终解决方式:DAO层按照数据源分包就可以了。

    总结:按照规范来说项目多数据源的时候都是需要进行分包的,这样比较容易区分管理。也会避免很多不必要的问题!!!

    展开全文
  • 原因:多数据源存在的问题: 最后一个可以插入一条数据,原因是Transactoinal的事务只针对userMapper有效。 二、使用springboot+jta+atomikos 分布式事物管理解决方案。 1、添加jta事务依赖 <dependency> ...

    一、为什么要配置多事务管理?

    原因:多数据源存在的问题:

    最后一个可以插入一条数据,原因是Transactoinal的事务只针对userMapper有效。
    在这里插入图片描述

    二、使用springboot+jta+atomikos 分布式事物管理解决方案。

    1、添加jta事务依赖

    <dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-jta-atomikos</artifactId>
    </dependency>
    

    2、修改数据库连接配置application.properties数据

    # Mysql 1
    mysql.datasource.test1.url = jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.test1.username = root
    mysql.datasource.test1.password = 123456
    mysql.datasource.test1.minPoolSize = 3
    mysql.datasource.test1.maxPoolSize = 25
    mysql.datasource.test1.maxLifetime = 20000
    mysql.datasource.test1.borrowConnectionTimeout = 30
    mysql.datasource.test1.loginTimeout = 30
    mysql.datasource.test1.maintenanceInterval = 60
    mysql.datasource.test1.maxIdleTime = 60
    mysql.datasource.test1.testQuery = select 1
    # Mysql 2
    mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.test2.username =root
    mysql.datasource.test2.password =123456
    mysql.datasource.test2.minPoolSize = 3
    mysql.datasource.test2.maxPoolSize = 25
    mysql.datasource.test2.maxLifetime = 20000
    mysql.datasource.test2.borrowConnectionTimeout = 30
    mysql.datasource.test2.loginTimeout = 30
    mysql.datasource.test2.maintenanceInterval = 60
    mysql.datasource.test2.maxIdleTime = 60
    mysql.datasource.test2.testQuery = select 1
    

    3、添加2个配置模型

    @ConfigurationProperties("mysql.datasource.test1")
    public class DBConfig1 {
    	private String url;
    	private String username;
    	private String password;
    	private int minPoolSize;
    	private int maxPoolSize;
    	private int maxLifetime;
    	private int borrowConnectionTimeout;
    	private int loginTimeout;
    	private int maintenanceInterval;
    	private int maxIdleTime;
    	private String testQuery;
    	}
    
    @ConfigurationProperties("mysql.datasource.test2")
    public class DBConfig2 {
    	private String url;
    	private String username;
    	private String password;
    	private int minPoolSize;
    	private int maxPoolSize;
    	private int maxLifetime;
    	private int borrowConnectionTimeout;
    	private int loginTimeout;
    	private int maintenanceInterval;
    	private int maxIdleTime;
    	private String testQuery;
    	}
    

    4、重定两个数据源配置

    @Configuration//注解到springboot容器中
    @MapperScan(basePackages="com.gyf.test1.mapper",sqlSessionFactoryRef="test1SqlSessionFactory")
    public class DataSource01 {
    	// 配置数据源
    		@Primary
    		@Bean(name = "test1DataSource")
    		public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
    			MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
    			mysqlXaDataSource.setUrl(testConfig.getUrl());
    			mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    			mysqlXaDataSource.setPassword(testConfig.getPassword());
    			mysqlXaDataSource.setUser(testConfig.getUsername());
    			mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    			AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
    			xaDataSource.setXaDataSource(mysqlXaDataSource);
    			xaDataSource.setUniqueResourceName("test1DataSource");
    			xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
    			xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
    			xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
    			xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
    			xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
    			xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
    			xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
    			xaDataSource.setTestQuery(testConfig.getTestQuery());
    			return xaDataSource;
    		}
    		@Bean(name = "test1SqlSessionFactory")
    		public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
    				throws Exception {
    			SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    			bean.setDataSource(dataSource);
    			return bean.getObject();
    		}
    		@Bean(name = "test1SqlSessionTemplate")
    		public SqlSessionTemplate testSqlSessionTemplate(
    				@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
    			return new SqlSessionTemplate(sqlSessionFactory);
    		}
    }
    
    @Configuration//注解到springboot容器中
    @MapperScan(basePackages="com.gyf.test2.mapper",sqlSessionFactoryRef="test2SqlSessionFactory")
    public class DataSource02 {
    	// 配置数据源
    		@Bean(name = "test2DataSource")
    		public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
    			MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
    			mysqlXaDataSource.setUrl(testConfig.getUrl());
    			mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    			mysqlXaDataSource.setPassword(testConfig.getPassword());
    			mysqlXaDataSource.setUser(testConfig.getUsername());
    			mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    			AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
    			xaDataSource.setXaDataSource(mysqlXaDataSource);
    			xaDataSource.setUniqueResourceName("test2DataSource");
    			xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
    			xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
    			xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
    			xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
    			xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
    			xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
    			xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
    			xaDataSource.setTestQuery(testConfig.getTestQuery());
    			return xaDataSource;
    		}
    		@Bean(name = "test2SqlSessionFactory")
    		public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
    				throws Exception {
    			SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    			bean.setDataSource(dataSource);
    			return bean.getObject();
    		}
    		@Bean(name = "test2SqlSessionTemplate")
    		public SqlSessionTemplate testSqlSessionTemplate(
    				@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
    			return new SqlSessionTemplate(sqlSessionFactory);
    		}
    }
    

    5、APP

    在这里插入图片描述

    展开全文
  • 最后使用到Spring+Ibatis多数据源,但使用过程中发生了用户访问错乱现象,具体表现为:使用数据源B用户去访问数据源A表,导致拒绝访问。 这个问题,经过多次尝试及网上搜索,发现问题所在:当一个事务发现...
  • 如果系统中存在多数据源,spring启动默认加载时,datasouce、session、transactionid值不能设置为相同,必须对其使用不同名称命名,否则将会出现数据调用问题。 如从mysql读取数据,则会始终提示no persistent ...
  •  因为整合了多数据源,就代表我项目中存在多个事物管理器,这样就不能直接使用@Transactional 修改代码: 修改user2接口模拟异常,查看事物是否回滚,添加@Transactional 启动测试: 访问user2接口报错 2021-01-28 12...
  • 针对这些问题,提出了一个基于多数据源的论文数据爬虫技术。首先,以知网、万方数据、维普网、超星期刊四大中文文献服务网站为数据源,针对检索关键词完成列表页数据爬取与解析;然后通过任务调度策略,去除各数据...
  • springboot-...通过分包实现多数据源的,检测多数据源存在的事务管理问题 multipledatasources3: 通过jta-atomikos解决传统项目多数据源事务管理问题 multipledatasources4: 通过aop的方式实现多数据源
  • 如果解决了那会不会有分布式事务的问题(解决的方案可能是分不同事务去解决的,那不同事务就存在事务一致性(分布式事务的问题)) 一、实现多数据源的方式 实现多数据源的方式主要有三种 1、不同包(实际不...
  • 2019-03-26 20:50:40.098 INFO 12972 — [nio-8081-exec-1] o.a.p.query.ConnectionQueryServicesImpl : HConnection established. Stacktrace for informational purposes: hconnection-0x5e689fc java.lang.Threa....
  • 遇到无法切换的问题 原因是具体操作的服务调用的是异步线程 mp的切换数据源信息是放在ThreadLocal中去存储的,如果切换了线程,那么就取不到数据源信息的内容,导致无法切换数据源的问题 对于这种情况,如果异步有...
  • 本文主要介绍如何使用ApacheSpark中的DataSourceAPI以实现多个数据源混合计算的实践,那么这么做的意义何在,其主要归结于3个方面:首先,我们身边存在大量的...下面一起讨论这两种解决方案中存在的问题:图1多数据源
  • 前言:本来想使用sharding-jdbc来实现这个,但是又不想不太熟悉新的框架而存在的坑而导致出现无法预测的问题或者及时的解决问题。因此按照实际开发习惯,使用原来简单项目,不引入新的框架,对JPA进行封装来实现...
  • 配置多数据源及多个jdbcTemple

    千次阅读 2016-04-13 14:26:14
    java配置数据源时,存在多个jdbcTemple不实例化的问题的处理。
  • 问题 ...这样就需要使用多数据源的技术。多数据源配置本身比较简单,但有一个场景出现了问题。考虑如下代码: // 通过try-catch实现insertOrUpdate Data data = new Data(); try{ dataM...
  • 版本 dynamic-datasource-spring-boot-starte v3.4.0 dynamic-datasource文档地址 ...怎么集成dynamic多数据源在项目文档写很清楚 文档地址 问题解决 自定义数据源加载类DatasourceConfig import com.
  • Spring多数据源实现

    2017-03-03 10:06:55
    这样存在的问题是由于每个数据源有自己的一套连接方式,导致代码冗余比较多。多数据源问题,归根结底是连接串的地址不一样(DataSource配置不一样),Spring提供了在DataSource层多数据源切换方式

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,381
精华内容 552
关键字:

多数据源存在的问题