• spring-boot支持双数据源mysql+mongo


    这里,首先想说的是,现在的web应用,处理的数据对象,有结构化的,也有非结构化的。同时存在。但是在spring-boot操作数据库的时候,若是在properties文件中配置数据源的信息,通过默认配置加载数据源的话,往往只会启动一个。

    我出于想弄清如何配置数据源的目的,在这里demo一个配置两个数据源的例子。分别是mysql和mongo。mysql的持久化采用的是mybatis。

    mongo的操作比较简单,直接贴上配置数据库的代码:

     1 package com.shihuc.dbconn.sourceconfig.mongo;
     2 
     3 import java.util.Arrays;
     4 
     5 import org.springframework.beans.factory.annotation.Value;
     6 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
     7 import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
     8 import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
     9 import org.springframework.context.annotation.Bean;
    10 import org.springframework.context.annotation.ComponentScan;
    11 import org.springframework.context.annotation.Configuration;
    12 import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
    13 import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
    14 
    15 import com.mongodb.Mongo;
    16 import com.mongodb.MongoClient;
    17 import com.mongodb.MongoCredential;
    18 import com.mongodb.ServerAddress;
    19 import com.mongodb.WriteConcern;
    20 
    21 @Configuration
    22 @EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
    23 @ComponentScan
    24 @EnableMongoRepositories
    25 public class MongoDataSourceConfig extends AbstractMongoConfiguration{
    26 
    27     @Value("${mongo.database}")
    28     private String dbname;
    29     
    30     @Value("${mongo.host}")
    31     private String dbhost;
    32     
    33     @Value("${mongo.port}")
    34     private String dbport;
    35     
    36     @Value("${mongo.username}")
    37     private String username;
    38     
    39     @Value("${mongo.password}")
    40     private String password;
    41     
    42     @Override
    43     protected String getDatabaseName() {
    44         return this.dbname;
    45     }
    46     
    47     public MongoDataSourceConfig(){
    48         if(null == dbport || "".equalsIgnoreCase(dbport.trim())){
    49             dbport = "27017";
    50         }
    51     }
    52 
    53     @Override
    54     @Bean(name = "mongods")
    55     public Mongo mongo() throws Exception {
    56         ServerAddress serverAdress = new  ServerAddress(dbhost, Integer.valueOf(dbport));        
    57         MongoCredential credential = MongoCredential.createMongoCRCredential(username, dbname , password.toCharArray());
    58         //Do not use new Mongo(), is deprecated.
    59         Mongo mongo =  new MongoClient(serverAdress, Arrays.asList(credential));
    60         mongo.setWriteConcern(WriteConcern.SAFE);
    61         return mongo;
    62     }
    63 }

    mongo数据库配置继承AbstractMongoConfiguration,在这个过程中,会向spring容器注册一个mongoTemplate,这个很重要,后期操作mongo数据库时,主要靠它。

    这里重点说下spring-boot和mybatis集成操作mysql的配置和注意事项。

     1 package com.shihuc.dbconn.sourceconfig.mysql;
     2 
     3 import javax.sql.DataSource;
     4 
     5 import org.springframework.beans.factory.annotation.Value;
     6 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
     7 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
     8 import org.springframework.context.annotation.Bean;
     9 import org.springframework.context.annotation.Configuration;
    10 import org.springframework.jdbc.datasource.DriverManagerDataSource;
    11 
    12 @Configuration
    13 @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
    14 public class MysqlDataSourceConfig {
    15 
    16     @Value("${mysql.driver}")
    17     private String driver;
    18 
    19     @Value("${mysql.url}")
    20     private String url;
    21 
    22     @Value("${mysql.username}")
    23     private String username;
    24 
    25     @Value("${mysql.password}")
    26     private String password;
    27 
    28     @Bean(name="mysqlds")
    29     public DataSource mysql()
    30     {
    31         DriverManagerDataSource ds = new DriverManagerDataSource();
    32         ds.setDriverClassName(driver);
    33         ds.setUrl(url);
    34         ds.setUsername(username);
    35         ds.setPassword(password);
    36         return ds;
    37     }
    38 }

    这个是datasource的配置,注意,类似mongo的配置,要将自动配置的类给exclude掉。让spring只处理我们希望的数据源。否则会受到classpath下的信息,干扰数据源的配置。

    另外,就是mybatis的配置。由于spring-boot重点特色是纯java config,所以,这里也采用java配置和注解启用mybatis。

     1 package com.shihuc.dbconn.sourceconfig.mysql;
     2 
     3 import javax.sql.DataSource;
     4 
     5 import org.apache.ibatis.session.SqlSessionFactory;
     6 import org.mybatis.spring.SqlSessionFactoryBean;
     7 import org.mybatis.spring.annotation.MapperScan;
     8 import org.springframework.beans.factory.annotation.Autowired;
     9 import org.springframework.beans.factory.annotation.Qualifier;
    10 import org.springframework.context.annotation.Bean;
    11 import org.springframework.context.annotation.Configuration;
    12 
    13 @Configuration
    14 @MapperScan(basePackages = "com.shihuc.dbconn.dao.mysql")
    15 public class MysqlMybatisConfig {
    16     
    17     @Autowired
    18     @Qualifier("mysqlds")
    19     private DataSource mysqlds;
    20     
    21     @Bean
    22     public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
    23         final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    24         sessionFactory.setDataSource(mysqlds);
    25         return sessionFactory.getObject();
    26     }
    27 }

    这里,mapperscan主要是为配置JavaBean和持久化对象之间的映射关系设定根路径。在这个例子中,mapper部分,其实就是通过insert,delete,update,select等注解,结合具体的SQL语句实现ORM的关系。看看这里的代码:

     1 package com.shihuc.dbconn.dao.mysql;
     2 
     3 import org.apache.ibatis.annotations.Insert;
     4 import org.apache.ibatis.annotations.Select;
     5 
     6 import com.shihuc.dbconn.pojo.mysql.MysqlUser;
     7 
     8 public interface IMysqlUser {
     9 
    10     @Select("SELECT * FROM user WHERE id = #{userId}")
    11     public MysqlUser getUser(int userId);
    12 
    13     @Insert("insert into user (username, job, age, hometown) values(#{username}, #{job}, #{age}, #{hometown})")
    14     public int addUser(MysqlUser user);
    15 }

    另外,配合这个IMysqlUser使用的MysqlUser的定义也很重要,主要是里面的constructor函数,通常,添加数据,比如上面的addUser操作,是要创建一个POJO的对象,为了方便,一般都会创建一个带参数的构造函数,注意,必须也同时创建一个无参数的构造函数,否则,在做查询操作,比如上面的getUser时,会出现下面的错误:

     1   .   ____          _            __ _ _
     2  /\ / ___'_ __ _ _(_)_ __  __ _    
     3 ( ( )\___ | '_ | '_| | '_ / _` |    
     4  \/  ___)| |_)| | | | | || (_| |  ) ) ) )
     5   '  |____| .__|_| |_|_| |_\__, | / / / /
     6  =========|_|==============|___/=/_/_/_/
     7  :: Spring Boot ::        (v1.2.7.RELEASE)
     8 
     9 2016-01-29 15:01:07.930  INFO 30880 --- [           main] com.shihuc.dbconn.DbConnApp              : Starting DbConnApp on CloudGame with PID 30880 (/home/webWps/dbconn/target/classes started by root in /home/webWps/dbconn)
    10 2016-01-29 15:01:07.997  INFO 30880 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@a85aa40: startup date [Fri Jan 29 15:01:07 CST 2016]; root of context hierarchy
    11 2016-01-29 15:01:09.887  INFO 30880 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'mysqlDataSourceConfig' of type [class com.shihuc.dbconn.sourceconfig.mysql.MysqlDataSourceConfig$$EnhancerBySpringCGLIB$$63c6820a] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    12 2016-01-29 15:01:09.915  INFO 30880 --- [           main] o.s.j.d.DriverManagerDataSource          : Loaded JDBC driver: com.mysql.jdbc.Driver
    13 2016-01-29 15:01:09.923  INFO 30880 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'mysqlds' of type [class org.springframework.jdbc.datasource.DriverManagerDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    14 2016-01-29 15:01:09.926  INFO 30880 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'mysqlMybatisConfig' of type [class com.shihuc.dbconn.sourceconfig.mysql.MysqlMybatisConfig$$EnhancerBySpringCGLIB$$bbfde9e4] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    15 2016-01-29 15:01:09.991  INFO 30880 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'sqlSessionFactoryBean' of type [class org.apache.ibatis.session.defaults.DefaultSqlSessionFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    16 2016-01-29 15:01:10.040  INFO 30880 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'IMysqlUser' of type [class org.mybatis.spring.mapper.MapperFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    17 2016-01-29 15:01:10.876  INFO 30880 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    18 2016-01-29 15:01:10.888  INFO 30880 --- [           main] com.shihuc.dbconn.DbConnApp              : Started DbConnApp in 3.274 seconds (JVM running for 3.561)
    19 Exception in thread "main" org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Error instantiating class com.shihuc.dbconn.pojo.mysql.MysqlUser with invalid types () or values (). Cause: java.lang.NoSuchMethodException: com.shihuc.dbconn.pojo.mysql.MysqlUser.<init>()
    20     at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:75)
    21     at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371)
    22     at com.sun.proxy.$Proxy26.selectOne(Unknown Source)
    23     at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:163)
    24     at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
    25     at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:43)
    26     at com.sun.proxy.$Proxy34.getUser(Unknown Source)
    27     at com.shihuc.dbconn.service.mysql.MysqlUserService.getUser(MysqlUserService.java:20)
    28     at com.shihuc.dbconn.DbConnApp.main(DbConnApp.java:34)
    29 Caused by: org.apache.ibatis.reflection.ReflectionException: Error instantiating class com.shihuc.dbconn.pojo.mysql.MysqlUser with invalid types () or values (). Cause: java.lang.NoSuchMethodException: com.shihuc.dbconn.pojo.mysql.MysqlUser.<init>()
    30     at org.apache.ibatis.reflection.factory.DefaultObjectFactory.instantiateClass(DefaultObjectFactory.java:83)
    31     at org.apache.ibatis.reflection.factory.DefaultObjectFactory.create(DefaultObjectFactory.java:45)
    32     at org.apache.ibatis.reflection.factory.DefaultObjectFactory.create(DefaultObjectFactory.java:38)
    33     at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:530)
    34     at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:509)
    35     at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:329)
    36     at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:289)
    37     at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:264)
    38     at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:234)
    39     at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:152)
    40     at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:57)
    41     at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:70)
    42     at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:57)
    43     at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:259)
    44     at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:132)
    45     at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:105)
    46     at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)
    47     at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:104)
    48     at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:98)
    49     at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:62)
    50     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    51     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    52     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    53     at java.lang.reflect.Method.invoke(Method.java:606)
    54     at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358)
    55     ... 7 more
    56 Caused by: java.lang.NoSuchMethodException: com.shihuc.dbconn.pojo.mysql.MysqlUser.<init>()
    57     at java.lang.Class.getConstructor0(Class.java:2892)
    58     at java.lang.Class.getDeclaredConstructor(Class.java:2058)
    59     at org.apache.ibatis.reflection.factory.DefaultObjectFactory.instantiateClass(DefaultObjectFactory.java:57)
    60     ... 31 more
    61 2016-01-29 15:01:11.139  INFO 30880 --- [       Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@a85aa40: startup date [Fri Jan 29 15:01:07 CST 2016]; root of context hierarchy
    62 2016-01-29 15:01:11.142  INFO 30880 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown
    View Code

    方便说明问题,将MysqlUser也附上代码:

     1 package com.shihuc.dbconn.pojo.mysql;
     2 
     3 import com.shihuc.dbconn.pojo.User;
     4 
     5 public class MysqlUser extends User{
     6 
     7     private static final long serialVersionUID = -6412107575129572581L;
     8 
     9     //这个id是数据库中通过设置auto_increment得到的主键值
    10     private int id;
    11 
    12     public int getId() {
    13         return id;
    14     }
    15 
    16     public void setId(int id) {
    17         this.id = id;
    18     }
    19     
    20     public MysqlUser(){
    21         
    22     }
    23     
    24     public MysqlUser(String username, String job, int age, String hometown){
    25         this.username = username;
    26         this.job = job;
    27         this.age = age;
    28         this.hometown = hometown;
    29     }
    30     
    31 }

    下面看看,测试程序吧,我是在main函数里面写的,如下:

     1 package com.shihuc.dbconn;
     2 
     3 import org.springframework.boot.SpringApplication;
     4 import org.springframework.boot.autoconfigure.SpringBootApplication;
     5 import org.springframework.context.ApplicationContext;
     6 import org.springframework.context.annotation.PropertySource;
     7 
     8 import com.shihuc.dbconn.pojo.mongo.MongoUser;
     9 import com.shihuc.dbconn.pojo.mysql.MysqlUser;
    10 import com.shihuc.dbconn.service.mongo.MongoUserService;
    11 import com.shihuc.dbconn.service.mysql.MysqlUserService;
    12 
    13 /**
    14  * 
    15  * @author  shihuc
    16  * @date    Jan 29, 2016
    17  * 
    18  */
    19 @SpringBootApplication
    20 @PropertySource(value = "dbconn.properties")
    21 public class DbConnApp 
    22 {
    23     
    24        public static void main(String[] args) throws Throwable {
    25           
    26         SpringApplication app = new SpringApplication(DbConnApp.class);
    27         
    28         ApplicationContext ctx = app.run(args);        
    29         
    30         MysqlUserService mysqlUserService = (MysqlUserService)ctx.getBean("mysqlUserService");        
    31 //        MysqlUser su = new MysqlUser("shihuc", "SW", 30 , "wuhan");
    32 //        mysqlUserService.addUser(su);    
    33         MysqlUser ue = mysqlUserService.getUser(1);
    34         System.out.println("Mysql User: " + ue);        
    35         
    36         MongoUserService mongoUserService = (MongoUserService)ctx.getBean("mongoUserService");
    37 //        MongoUser mu = new MongoUser("shihuc", "SW", 30 , "wuhan");
    38 //        mongoUserService.addUser(mu);                
    39         MongoUser um = mongoUserService.getUser("shihuc");
    40         System.out.println("Mongo User: " + um);
    41     }
    42 }

    最后附上我的maven项目的pom文件:

     1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     2   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     3   <modelVersion>4.0.0</modelVersion>
     4 
     5   <groupId>com.shihuc</groupId>
     6   <artifactId>dbconn</artifactId>
     7   <version>0.0.1-SNAPSHOT</version>
     8   <packaging>jar</packaging>
     9 
    10   <name>dbconn</name>
    11   <url>http://maven.apache.org</url>
    12 
    13   <parent>
    14         <groupId>org.springframework.boot</groupId>
    15         <artifactId>spring-boot-starter-parent</artifactId>
    16         <version>1.2.7.RELEASE</version>
    17   </parent>
    18   
    19   <properties>
    20     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    21   </properties>
    22 
    23   <dependencies>
    24       <dependency>
    25           <groupId>org.springframework.boot</groupId>
    26         <artifactId>spring-boot-starter-jdbc</artifactId>        
    27     </dependency>
    28     <dependency>
    29         <groupId>mysql</groupId>
    30         <artifactId>mysql-connector-java</artifactId>
    31         </dependency>
    32     <dependency>
    33         <groupId>org.mybatis</groupId>
    34         <artifactId>mybatis</artifactId>
    35         <version>3.2.3</version>
    36     </dependency>
    37     <dependency>
    38         <groupId>org.mybatis</groupId>
    39         <artifactId>mybatis-spring</artifactId>
    40         <version>1.2.2</version>
    41     </dependency>
    42     <dependency>
    43         <groupId>org.springframework.boot</groupId>
    44         <artifactId>spring-boot-starter-data-mongodb</artifactId>
    45     </dependency>
    46   </dependencies>
    47   
    48   <build>
    49     <plugins>
    50         <plugin>
    51             <groupId>org.springframework.boot</groupId>
    52             <artifactId>spring-boot-maven-plugin</artifactId>
    53         </plugin>
    54     </plugins>
    55   </build>
    56 </project>

    还是相对比较简单的配置和操作。对于这个demo的例子程序,可以在GitHub https://github.com/shihuc/dbconn上下载。

  • 相关阅读:
    关于OI的文学作品
    HBOI 2020 游记
    从0开始的字符串生活(选手命要没了)
    近两年HBOI选做
    NOI online #3
    2020年“美团杯”程序设计挑战赛题解(目前只有测试赛)
    退群咕咕墙
    JS 获得当前地址栏url
    你了解getBoundingClientRect()?
    字符串与数字相加
  • 原文地址:https://www.cnblogs.com/shihuc/p/5169418.html
Copyright © 2020-2023  润新知