43. Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

 

【视频 & 交流平台】

à SpringBoot视频

http://study.163.com/course/introduction.htm?courseId=1004329008&utm_campaign=commission&utm_source=400000000155061&utm_medium=share

à SpringCloud视频

http://study.163.com/course/introduction.htm?courseId=1004638001&utm_campaign=commission&utm_source=400000000155061&utm_medium=share

à Spring Boot源码

https://gitee.com/happyangellxq520/spring-boot

à Spring Boot交流平台

http://412887952-qq-com.iteye.com/blog/2321532

 


 

 


在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库。那么这一节我们将要介绍怎么进行多数据源动态切换。添加本文实现的代码之后,只需要配置要数据源就可以直接通过注解使用,在实际使用的时候特别的简单。那么本章主要分以下几个步骤进行实战。

(1)新建maven javaproject;

(2)在pom.xml添加依赖包;

(3)编写启动类App.java

(4)编写配置文件application.properties;

(5)动态数据源路由类;

(6)注册多数据源;

(7)测试类测试;

 

       接下来我们看看每一步具体的实现吧:

 

(1)新建maven java project;

       新建一个maven project,取名为:spring-boot-multi-ds

(2)在pom.xml添加依赖包;

       在pom.xml文件中加入依赖的库文件,主要是springboot基本的,数据库驱动,spring-jpa支持即可,具体pom.xml文件如下:

<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">

 <modelVersion>4.0.0</modelVersion>

 

 <groupId>com.kfit</groupId>

 <artifactId>spring-boot-multids</artifactId>

 <version>0.0.1-SNAPSHOT</version>

 <packaging>jar</packaging>

 

 <name>spring-boot-multids</name>

 <url>http://maven.apache.org</url>

 

 <properties>

   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

   <!--jdk版本号,这里需要你本地进行的jdk进行修改,这里angel使用的是1.8的版本. -->

   <java.version>1.8</java.version>

 </properties>

 

 

  <!--

              springboot父节点依赖,

             引入这个之后相关的引入就不需要添加version配置,

              springboot会自动选择最合适的版本进行添加。

             在这里使用的1.3.3版本,可能目前官方有最新的版本了,大家可以

             使用最新的版本。

        -->

       <parent>

              <groupId>org.springframework.boot</groupId>

              <artifactId>spring-boot-starter-parent</artifactId>

              <version>1.3.3.RELEASE</version>

       </parent>

 

 <dependencies>

     <!-- 单元测试包,在这里没有使用到.-->

   <dependency>

     <groupId>junit</groupId>

     <artifactId>junit</artifactId>

     <scope>test</scope>

   </dependency>

   

   <!-- spring boot web支持:mvc,aop...

         这个是最基本的,基本每一个基本的demo都是需要引入的。

   -->

       <dependency>

              <groupId>org.springframework.boot</groupId>

              <artifactId>spring-boot-starter-web</artifactId>

       </dependency>

      

       <!-- mysql驱动.

             我们的demo是多数据源,在这里使用Mysql数据库.

       -->

       <dependency>

              <groupId>mysql</groupId>

              <artifactId>mysql-connector-java</artifactId>

       </dependency>

      

      

       <!-- springjpa

              springjpa中带有自带的tomcat 数据连接池;

             在代码中我们也需要用到.

        -->

       <dependency>

              <groupId>org.springframework.boot</groupId>

              <artifactId>spring-boot-starter-data-jpa</artifactId>

       </dependency>

   

 </dependencies>

</project>

       在上面的配置文件中都有相应的解释,大家可以自己解读下。

 

 

(3)编写启动类App.java

       编写spring boot的启动类:

com.kfit.App:

package com.kfit;

 

import org.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

 

/**

 *

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@SpringBootApplication

publicclass App {

       publicstaticvoid main(String[]args) {

              SpringApplication.run(App.class,args);

       }

}

 

 

(4)编写配置文件application.properties;

       在这里主要是多数据源和jpa的配置:

src/main/resources/application.properties:

########################################################

###配置文件包括1个主数据源和多个数据源,

###其中主数据源在Spring中的beanName默认为dataSource,

###另外几个数据源的beanName分包为:ds1、ds2、ds3

###其中datasource的type属性可以具体指定到我们需要的数据源上面,

###不指定情况下默认为:org.apache.tomcat.jdbc.pool.DataSource

###当然你也可以把这些数据源配置到主dataSource数据库中,然后读取数据库生成多数据源。当然这样做的必要性并不大,难不成数据源还会经常变吗。

########################################################

 

#主数据源,默认的

#spring.datasource.type=com.zaxxer.hikari.HikariDataSource

spring.datasource.driverClassName=com.mysql.jdbc.Driver

spring.datasource.url=jdbc:mysql://localhost:3306/test

spring.datasource.username=root

spring.datasource.password=root

 

 

#更多数据源

custom.datasource.names=ds1,ds2,ds3

#custom.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource

custom.datasource.ds1.driverClassName=com.mysql.jdbc.Driver

custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test1

custom.datasource.ds1.username=root

custom.datasource.ds1.password=root

 

#custom.datasource.ds2.type=com.zaxxer.hikari.HikariDataSource

custom.datasource.ds2.driverClassName=com.mysql.jdbc.Driver

custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test

custom.datasource.ds2.username=root

custom.datasource.ds2.password=root

 

#custom.datasource.ds3.type=com.zaxxer.hikari.HikariDataSource

custom.datasource.ds3.driverClassName=com.mysql.jdbc.Driver

custom.datasource.ds3.url=jdbc:mysql://localhost:3306/test

custom.datasource.ds3.username=root

custom.datasource.ds3.password=root

 

 

#下面为连接池的补充设置,应用到上面所有数据源中

spring.datasource.maximum-pool-size=100

spring.datasource.max-idle=10

spring.datasource.max-wait=10000

spring.datasource.min-idle=5

spring.datasource.initial-size=5

spring.datasource.validation-query=SELECT 1

spring.datasource.test-on-borrow=false

spring.datasource.test-while-idle=true

spring.datasource.time-between-eviction-runs-millis=18800

 

 

 

########################################################

### Java Persistence Api

########################################################

# Specify the DBMS

spring.jpa.database= MYSQL

# Show or not log for each sqlquery

spring.jpa.show-sql= true

# Hibernate ddl auto (create,create-drop, update)

spring.jpa.hibernate.ddl-auto= update

# Naming strategy

#[org.hibernate.cfg.ImprovedNamingStrategy  #org.hibernate.cfg.DefaultNamingStrategy]

spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy

# stripped before adding them tothe entity manager)

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

 

 

 

(5)动态数据源路由类;

       动态数据源能进行自动切换的核心就是spring底层提供了AbstractRoutingDataSource类进行数据源的路由的,我们主要继承这个类,实现里面的方法即可实现我们想要的,这里主要是实现方法:determineCurrentLookupKey(),而此方法只需要返回一个数据库的名称即可,所以我们核心的是有一个类来管理数据源的线程池,这个类才是动态数据源的核心处理类。还有另外就是我们使用aop技术在执行事务方法前进行数据源的切换。所以这里有几个需要编码的类,具体如下:

 

动态数据源上下文>com.kfit.config.datasource.DynamicDataSourceContextHolder:

package com.kfit.config.datasource.dynamic;

 

import java.util.ArrayList;

import java.util.List;

 

/**

 *动态数据源上下文.

 *

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

publicclass DynamicDataSourceContextHolder {

      

       /*

        *当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,

        *所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

        */

       privatestaticfinalThreadLocal<String>contextHolder =new ThreadLocal<String>();

       /*

        *管理所有的数据源id;

        *主要是为了判断数据源是否存在;

        */

       publicstaticList<String>dataSourceIds =new ArrayList<String>();

 

       /**

        *使用setDataSourceType设置当前的

        *@param dataSourceType

        */

       publicstaticvoidsetDataSourceType(StringdataSourceType) {

              contextHolder.set(dataSourceType);

       }

 

       publicstatic StringgetDataSourceType() {

              returncontextHolder.get();

       }

 

       publicstaticvoidclearDataSourceType() {

              contextHolder.remove();

       }

      

       /**

    *判断指定DataSrouce当前是否存在

    *

    *@param dataSourceId

    *@return

    *@author SHANHY

    *@create  2016年1月24日

    */

   publicstaticboolean containsDataSource(StringdataSourceId){

        returndataSourceIds.contains(dataSourceId);

   }

}

 

数据源路由类>com.kfit.config.datasource.dynamic.DynamicDataSource:

package com.kfit.config.datasource.dynamic;

 

importorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

 

/**

 *动态数据源.

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

publicclass DynamicDataSourceextendsAbstractRoutingDataSource {

      

       /*

        *代码中的determineCurrentLookupKey方法取得一个字符串,

        *该字符串将与配置文件中的相应字符串进行匹配以定位数据源,配置文件,即applicationContext.xml文件中需要要如下代码:(non-Javadoc)

        * @seeorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()

        */

       @Override

       protected ObjectdetermineCurrentLookupKey() {

              /*

               * DynamicDataSourceContextHolder代码中使用setDataSourceType

               *设置当前的数据源,在路由类中使用getDataSourceType进行获取,

               * 交给AbstractRoutingDataSource进行注入使用。

               */

              returnDynamicDataSourceContextHolder.getDataSourceType();

       }

}

 

指定数据源注解类>com.kfit.config.datasource.dynamic.TargetDataSource:

package com.kfit.config.datasource.dynamic;

 

importjava.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

importjava.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

/**

 *在方法上使用,用于指定使用哪个数据源

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@Target({ ElementType.METHOD, ElementType.TYPE })

@Retention(RetentionPolicy.RUNTIME)

@Documented

public@interfaceTargetDataSource {

       Stringvalue();

}

 

切换数据源Advice>com.kfit.config.datasource.dynamic.DynamicDataSourceAspect:

package com.kfit.config.datasource.dynamic;

 

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

importorg.springframework.core.annotation.Order;

importorg.springframework.stereotype.Component;

 

/**

 *切换数据源Advice

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@Aspect

@Order(-10)//保证该AOP在@Transactional之前执行

@Component

publicclass DynamicDataSourceAspect {

      

       /*

        * @Before("@annotation(ds)")

        *的意思是:

        *

        * @Before:在方法执行之前进行执行:

        * @annotation(targetDataSource)

        *会拦截注解targetDataSource的方法,否则不拦截;

        */

       @Before("@annotation(targetDataSource)")

   publicvoid changeDataSource(JoinPointpoint, TargetDataSourcetargetDataSource) throws Throwable {

              //获取当前的指定的数据源;

        String dsId = targetDataSource.value();

        //如果不在我们注入的所有的数据源范围之内,那么输出警告信息,系统自动使用默认的数据源。

        if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {

            System.err.println("数据源[{}]不存在,使用默认数据源 > {}"+targetDataSource.value()+point.getSignature());

        } else {

               System.out.println("UseDataSource : {} > {}"+targetDataSource.value()+point.getSignature());

               //找到的话,那么设置到动态数据源上下文中。

            DynamicDataSourceContextHolder.setDataSourceType(targetDataSource.value());

        }

   }

      

       @After("@annotation(targetDataSource)")

   publicvoid restoreDataSource(JoinPointpoint, TargetDataSourcetargetDataSource) {

              System.out.println("RevertDataSource : {} > {}"+targetDataSource.value()+point.getSignature());

              //方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。

        DynamicDataSourceContextHolder.clearDataSourceType();

   }

      

}

 

 

(6)注册多数据源;

       以上都是动态数据源在注入的时候使用的代码,其实很重要的一部分代码就是注册我们在application.properties配置的多数据源,这才是重点,这里我们使用

ImportBeanDefinitionRegistrar进行注册,具体的代码如下:

package com.kfit.config.datasource.dynamic;

 

import java.util.HashMap;

import java.util.Map;

 

import javax.sql.DataSource;

 

importorg.springframework.beans.MutablePropertyValues;

import org.springframework.beans.PropertyValues;

importorg.springframework.beans.factory.support.BeanDefinitionRegistry;

importorg.springframework.beans.factory.support.GenericBeanDefinition;

importorg.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;

importorg.springframework.boot.bind.RelaxedDataBinder;

importorg.springframework.boot.bind.RelaxedPropertyResolver;

importorg.springframework.context.EnvironmentAware;

importorg.springframework.context.annotation.ImportBeanDefinitionRegistrar;

import org.springframework.core.convert.ConversionService;

importorg.springframework.core.convert.support.DefaultConversionService;

importorg.springframework.core.env.Environment;

importorg.springframework.core.type.AnnotationMetadata;

 

/**

 *动态数据源注册;

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

publicclass DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

      

       //如配置文件中未指定数据源类型,使用该默认值

   privatestaticfinal ObjectDATASOURCE_TYPE_DEFAULT ="org.apache.tomcat.jdbc.pool.DataSource";

   private ConversionServiceconversionService =newDefaultConversionService();

   private PropertyValuesdataSourcePropertyValues;

   

       // 默认数据源

   private DataSourcedefaultDataSource;

      

   private Map<String, DataSource>customDataSources =newHashMap<String, DataSource>();

   

       /**

        *加载多数据源配置

        */

       @Override

       publicvoidsetEnvironment(Environmentenvironment) {

              System.out.println("DynamicDataSourceRegister.setEnvironment()");

              initDefaultDataSource(environment);

        initCustomDataSources(environment);

       }

      

       /**

        *加载主数据源配置.

        *@param env

        */

       privatevoidinitDefaultDataSource(Environmentenv){

              // 读取主数据源

              RelaxedPropertyResolverpropertyResolver =newRelaxedPropertyResolver(env,"spring.datasource.");

              Map<String,Object>dsMap =new HashMap<String, Object>();

              dsMap.put("type", propertyResolver.getProperty("type"));

        dsMap.put("driverClassName", propertyResolver.getProperty("driverClassName"));

        dsMap.put("url", propertyResolver.getProperty("url"));

        dsMap.put("username", propertyResolver.getProperty("username"));

        dsMap.put("password", propertyResolver.getProperty("password"));

       

        //创建数据源;

        defaultDataSource =buildDataSource(dsMap);

        dataBinder(defaultDataSource,env);

       }

      

       /**

    *初始化更多数据源

    *

    *@author SHANHY

    *@create 2016年1月24日

    */

   privatevoid initCustomDataSources(Environmentenv) {

       //读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源

        RelaxedPropertyResolverpropertyResolver =newRelaxedPropertyResolver(env,"custom.datasource.");

        String dsPrefixs = propertyResolver.getProperty("names");

        for (StringdsPrefix :dsPrefixs.split(",")) {//多个数据源

            Map<String, Object>dsMap =propertyResolver.getSubProperties(dsPrefix +".");

            DataSource ds = buildDataSource(dsMap);

            customDataSources.put(dsPrefix, ds);

            dataBinder(ds,env);

        }

   }

      

       /**

        *创建datasource.

        *@param dsMap

        *@return

        */

       @SuppressWarnings("unchecked")

       public DataSourcebuildDataSource(Map<String, Object>dsMap) {

              Objecttype =dsMap.get("type");

        if (type ==null){

            type = DATASOURCE_TYPE_DEFAULT;//默认DataSource

        }

        Class<? extends DataSource>dataSourceType;

       

              try {

                     dataSourceType = (Class<? extends DataSource>)Class.forName((String)type);

                     StringdriverClassName =dsMap.get("driverClassName").toString();

               String url = dsMap.get("url").toString();

               String username = dsMap.get("username").toString();

               String password = dsMap.get("password").toString();

               DataSourceBuilderfactory =   DataSourceBuilder.create().driverClassName(driverClassName).url(url).username(username).password(password).type(dataSourceType);

               returnfactory.build();

              }catch(ClassNotFoundExceptione) {

                     e.printStackTrace();

              }

              returnnull;

       }

      

       /**

        *为DataSource绑定更多数据

        *@param dataSource

        *@param env

        */

       privatevoiddataBinder(DataSourcedataSource, Environment env){

              RelaxedDataBinderdataBinder =newRelaxedDataBinder(dataSource);

              dataBinder.setConversionService(conversionService);

              dataBinder.setIgnoreNestedProperties(false);//false

        dataBinder.setIgnoreInvalidFields(false);//false

        dataBinder.setIgnoreUnknownFields(true);//true

       

        if(dataSourcePropertyValues ==null){

            Map<String, Object>rpr =newRelaxedPropertyResolver(env,"spring.datasource").getSubProperties(".");

            Map<String, Object>values =newHashMap<>(rpr);

            // 排除已经设置的属性

            values.remove("type");

            values.remove("driverClassName");

            values.remove("url");

            values.remove("username");

            values.remove("password");

            dataSourcePropertyValues = new MutablePropertyValues(values);

        }

        dataBinder.bind(dataSourcePropertyValues);

       

       }

      

 

       @Override

       publicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry) {

              System.out.println("DynamicDataSourceRegister.registerBeanDefinitions()");

              Map<Object,Object>targetDataSources =new HashMap<Object, Object>();

              // 将主数据源添加到更多数据源中

        targetDataSources.put("dataSource", defaultDataSource);

        DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");

          // 添加更多数据源

        targetDataSources.putAll(customDataSources);

        for (Stringkey :customDataSources.keySet()) {

            DynamicDataSourceContextHolder.dataSourceIds.add(key);

        }

       

        // 创建DynamicDataSource

        GenericBeanDefinitionbeanDefinition =newGenericBeanDefinition();

        beanDefinition.setBeanClass(DynamicDataSource.class);

       

        beanDefinition.setSynthetic(true);

        MutablePropertyValuesmpv =beanDefinition.getPropertyValues();

        //添加属性:AbstractRoutingDataSource.defaultTargetDataSource

        mpv.addPropertyValue("defaultTargetDataSource",defaultDataSource);

        mpv.addPropertyValue("targetDataSources",targetDataSources);

        registry.registerBeanDefinition("dataSource",beanDefinition);

       }

 

}

这里还有一个步骤很重要,由于我们是使用的ImportBeanDefinitionRegistrar的方式进行注册的,所以我们需要在App.java类中使用@Import进行注册,具体改造之后的App.java代码如下:

package com.kfit;

 

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.annotation.Import;

importcom.kfit.config.datasource.dynamic.DynamicDataSourceRegister;

 

/**

 *

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@SpringBootApplication

//注册动态多数据源

@Import({DynamicDataSourceRegister.class})

publicclass App {

       publicstaticvoid main(String[]args) {

              SpringApplication.run(App.class,args);

       }

}

 

 

(7)测试类测试;

       核心的代码都编写完毕了,当然我们肯定是需要编写代码进行测试下,我们才放心了。

com.kfit.demo.bean.Demo:

package com.kfit.demo.bean;

 

import javax.persistence.Entity;

importjavax.persistence.GeneratedValue;

import javax.persistence.Id;

 

/**

 *测试demo类.

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@Entity

publicclass Demo {

       @Id @GeneratedValue

       privatelongid;

      

       private Stringname;

 

       publiclong getId() {

              returnid;

       }

 

       publicvoid setId(longid) {

              this.id =id;

       }

 

       public StringgetName() {

              returnname;

       }

 

       publicvoid setName(Stringname) {

              this.name =name;

       }

 

       @Override

       public StringtoString() {

              return"Demo[id=" +id +", name=" +name +"]";

       }

}

 

com.kfit.demo.dao.TestDao:

package com.kfit.demo.dao;

 

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.List;

 

importorg.springframework.beans.factory.annotation.Autowired;

importorg.springframework.jdbc.core.JdbcTemplate;

importorg.springframework.jdbc.core.RowMapper;

import org.springframework.stereotype.Service;

 

import com.kfit.demo.bean.Demo;

 

@Service

publicclass TestDao {

      

       @Autowired

   private JdbcTemplatejdbcTemplate;

      

       /**

        *不指定数据源使用默认数据源

        *@return

        */

       publicList<Demo> getList(){

              Stringsql ="select*from Demo";

        return (List<Demo>)jdbcTemplate.query(sql,newRowMapper<Demo>(){

            @Override

            public Demo mapRow(ResultSetrs,introwNum)throws SQLException {

                   Demodemo =new Demo();

                   demo.setId(rs.getLong("id"));

                   demo.setName(rs.getString("name"));;

                returndemo;

            }

        });

       }

      

        /**

    *指定数据源

    *在对应的service进行指定;

    *@return

    *@author SHANHY

    *@create  2016年1月24日

    */

   public List<Demo> getListByDs1(){

          /*

           *这张表示复制的主库到ds1的,在ds中并没有此表.

           *需要自己自己进行复制,不然会报错:Table 'test1.demo1'doesn't exist

           */

              Stringsql ="select*from Demo1";

        return(List<Demo>)jdbcTemplate.query(sql,new RowMapper<Demo>(){

 

            @Override

            publicDemo mapRow(ResultSetrs, introwNum) throws SQLException {

                   Demodemo =new Demo();

                   demo.setId(rs.getLong("id"));

                   demo.setName(rs.getString("name"));;

                returndemo;

            }

 

        });

   }

}

 

com.kfit.demo.service.TestService :

package com.kfit.demo.service;

 

import java.util.List;

 

import javax.annotation.Resource;

 

importorg.springframework.stereotype.Service;

 

importcom.kfit.config.datasource.dynamic.TargetDataSource;

import com.kfit.demo.bean.Demo;

import com.kfit.demo.dao.TestDao;

 

@Service

publicclass TestService {

      

       @Resource

       private TestDaotestDao;

      

       /**

        *不指定数据源使用默认数据源

        *@return

        */

       publicList<Demo> getList(){

              returntestDao.getList();

       }

      

       /**

        *指定数据源

        *@return

        */

   @TargetDataSource("ds1")

   public List<Demo> getListByDs1(){

          returntestDao.getListByDs1();

   }

}

 

com.kfit.demo.controller.TestController:

package com.kfit.demo.controller;

 

import javax.annotation.Resource;

 

importorg.springframework.web.bind.annotation.RequestMapping;

importorg.springframework.web.bind.annotation.RestController;

 

import com.kfit.demo.bean.Demo;

import com.kfit.demo.service.TestService;

 

@RestController

publicclass TestController {

      

       @Resource

       private TestServicetestService;

      

       @RequestMapping("/test1")

       public String test(){

//           for(Demod:testService.getList()){

//                  System.out.println(d);

//           }

              for(Demod:testService.getListByDs1()){

                     System.out.println(d);

              }

              return"ok";

       }

      

}

 

好了,测试代码就这么多了,运行App.java进行测试把,访问:

http://127.0.0.1:8080/test1查看控制台的打印。

这里需要提醒下,这种方式spring-jpa的方式好像不能自动路由,博主打算在之后的一篇文章介绍spring-jpa多数据源的问题。 


Spring Boot 系列视频】

视频&交流平台:

à Spring Boot网易云课堂视频

http://study.163.com/course/introduction.htm?courseId=1004329008

à Spring Boot交流平台

http://412887952-qq-com.iteye.com/blog/2321532

 

网易云课堂视频最新更新

第十一章 Spring Boot 日志

1、spring boot日志—理论

2、Spring Boot日志-logback

3、Spring Boot日志-log4j2

第十二章 Spring Boot 知识点2

1、spring boot 服务配置和部署

2、Spring Boot 定制URL匹配规则

 

 

历史章节

 

第一章 快速开始

1、Spring Boot之Hello World

2、Spring Boot之Hello World访问404

 

第二章 Spring Boot之JSON

1、spring boot返回json数据

2、Spring Boot完美使用FastJson解析JSON数据

 

第三章 Spring Boot热部署

1、Spring Boot热部署(springloader)

2、springboot + devtools(热部署)

 

第四章 Spring Boot数据库

1、Spring Boot JPA/Hibernate/Spring Data概念

2、Spring Boot JPA-Hibernate

3、Spring Boot Spring Data JPA介绍

4、Spring Boot JdbcTemplate

5、Spring Boot集成MyBatis

 

第五章 web开发

1、全局异常捕捉

2、配置server信息

3、spring boot使用thymeleaf

4、Spring Boot 使用freemarker

5、Spring Boot添加JSP支持

 

第六章 定时任务

1、Spring Boot定时任务

2、Spring Boot 定时任务升级篇(动态修改cron参数)

3、Spring Boot 定时任务升级篇(动态添加修改删除定时任务)

4、Spring Boot 定时任务升级篇(集群/分布式下的定时任务说明)

5、Spring Boot Quartz介绍

6、Spring Boot Quartz在Java Project中使用

7、Spring Boot 集成Quartz普通使用

8、Spring Boot 集成Quartz升级版

9、Spring Boot 集成Quartz二次升级版

10、Spring Boot 集成Quartz-Job如何自动注入Spring容器托管的对象

 

第七章 Spring Boot MyBatis升级篇

1、Spring Boot MyBatis升级篇-注解

2、Spring Boot MyBatis升级篇-注解-自增ID

3、Spring Boot MyBatis升级篇-注解-增删改查

4、Spring Boot MyBatis升级篇-注解-分页查询

5、Spring Boot MyBatis升级篇-注解-分页PageHelper不生效

6、Spring Boot MyBatis升级篇-注解- mybatic insert异常:BindingException: Parameter 'name' not found

7、Spring Boot MyBatis升级篇-注解- #和$符号特别篇

8、Spring Boot MyBatis升级篇-注解-@Result

9、Spring Boot MyBatis升级篇-注解-动态SQL(if test)-方案一:<script>

10、Spring Boot MyBatis升级篇-注解-动态SQL(if test)-方案二:@Provider

11、Spring Boot MyBatis升级篇-注解-动态SQL-参数问题

12、Spring Boot MyBatis升级篇-注解-特别篇:@MapperScan和@Mapper

13、Spring Boot MyBatis升级篇-XML

14、Spring Boot MyBatis升级篇-XML-自增ID

15、Spring Boot MyBatis升级篇-XML-增删改查

16、Spring Boot MyBatis升级篇-XML-分页查询

17、Spring Boot MyBatis升级篇-XML-分页PageHelper不生效

18、Spring Boot MyBatis升级篇-XML-动态SQL(if test)

19、Spring Boot MyBatis升级篇-XML-注解-初尝试

20、Spring Boot MyBatis升级篇- pagehelper替换为pagehelper-spring-boot-starter

 

第八章 Spring Boot 知识点1

1、Spring Boot 拦截器HandlerInterceptor

2、Spring Boot启动加载数据CommandLineRunner

3、Spring Boot环境变量读取和属性对象的绑定

4、Spring Boot使用自定义的properties

5、Spring Boot使用自定义的properties

6、Spring Boot使用@SpringBootApplication

7、Spring Boot 监控和管理生产环境

 

第十章 Spring Boot 打包部署

1、Spring Boot打包部署((提供Linux的sh文件))

 

第十一章 Spring Boot 日志

1、spring boot日志—理论

2、Spring Boot日志-logback

 

3、Spring Boot日志-log4j2



  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悟纤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值