多数据源配置主要涉及自定义类(DataSource注解类、DataSourceAspect切面类,动态数据源接口实现类、以及数据源字符串线程保存类),pom.xml文件、applicationContext.xml、mybatis相关配置,以及业务代码(test包),参考实际开发及网上资料记录下来。

一、配置文件

  1.pom.xml

  这里我用的是mac上的eclipse,maven版本是3.6.0,jdk版本是1.8,tomcat9。pom文件配置如下:

<project xmlns="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.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>laboratory</groupId>
<artifactId>mvclab</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>mcv Maven Webapp</name>
<url>http://maven.apache.org</url> <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>
<spring.version>5.1.5.RELEASE</spring.version>
<mybatis.version>3.2.8</mybatis.version>
<mybatis-spring.version>1.2.2</mybatis-spring.version>
<spring-jpa-version>1.3.2.RELEASE</spring-jpa-version>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency> <!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency> <!--tomcat所需jar包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency> <dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency> <!--返回object对象所需要的依赖,它在<mvc:annotation-driven>注册时注入-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency> <!-- 补充 -->
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency> <!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- dbcp数据源 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>mcv</finalName>
</build>
</project>

  2.applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- context:设置注解扫描包注解
注: 如果springmvc-servlet中扫描注解没有排除@Service注解,这里要设置扫描除@Controller之外的其它所有注解
-->
<context:component-scan base-package="com.mvc">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<!-- 自定义异常处理 -->
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan> <!-- 开启@Autowired注解扫描
注: 它等价于<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/>
注: 配置了<context:component-scan />,默认包含对@Autowired的配置,因此下面这个配置就不需要了
-->
<context:annotation-config/> <!-- 注册数据源配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 注册数据源对象 这里用Spring内置数据源 -->
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>${oracle11g.driverClass}</value>
</property>
<property name="url">
<value>${oracle11g.url}</value>
</property>
<property name="username">
<value>${oracle11g.username}</value>
</property>
<property name="password">
<value>${oracle11g.password}</value>
</property>
<property name="maxActive">
<value>${oracle11g.maxActive}</value>
</property>
<property name="maxIdle">
<value>${oracle11g.maxIdle}</value>
</property>
<property name="maxWait">
<value>${oracle11g.maxWait}</value>
</property>
<property name="defaultAutoCommit">
<value>${oracle11g.defaultAutoCommit}</value>
</property>
<property name="timeBetweenEvictionRunsMillis">
<value>${oracle11g.timeBetweenEvictionRunsMillis}</value>
</property>
<property name="minEvictableIdleTimeMillis">
<value>${oracle11g.minEvictableIdleTimeMillis}</value>
</property>
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>${oracle11g-1.driverClass}</value>
</property>
<property name="url">
<value>${oracle11g-1.url}</value>
</property>
<property name="username">
<value>${oracle11g-1.username}</value>
</property>
<property name="password">
<value>${oracle11g-1.password}</value>
</property>
<property name="maxActive">
<value>${oracle11g-1.maxActive}</value>
</property>
<property name="maxIdle">
<value>${oracle11g-1.maxIdle}</value>
</property>
<property name="maxWait">
<value>${oracle11g-1.maxWait}</value>
</property>
<property name="defaultAutoCommit">
<value>${oracle11g-1.defaultAutoCommit}</value>
</property>
<property name="timeBetweenEvictionRunsMillis">
<value>${oracle11g-1.timeBetweenEvictionRunsMillis}</value>
</property>
<property name="minEvictableIdleTimeMillis">
<value>${oracle11g-1.minEvictableIdleTimeMillis}</value>
</property>
</bean>
<!-- 配置动态数据源 -->
<bean id="dynamicDataSource" class="com.mvc.dynamicDataSource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- 指定lookupKey和与之对应的数据源 -->
<entry key="dataSource1" value-ref="dataSource1" />
<entry key="dataSource2" value-ref="dataSource2" />
</map>
</property>
<!-- 指定默认的数据源 -->
<property name="defaultTargetDataSource" ref="dataSource1" />
</bean> <!-- 配置事务管理对象,注意这里设置的是dataSource1而不是dynamicDataSource-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource1" />
</bean>
<!-- 将所有具有@Transactional注解的Bean自动配置为声明式事务支持 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> <!-- MyBatis 数据源和sql- -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
<property name="mapperLocations" value="classpath:/mappings/**/*.xml"/>
<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
</bean>
<!-- MyBayis 扫描器配置-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.mvc.laboratory"/>
</bean> <!--接收json数据-->
<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean> <!-- 配置事务自动代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
</beans>

  3.mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局参数 -->
<settings>
<!-- 使全局的映射器启用或禁用缓存。 -->
<setting name="cacheEnabled" value="true"/>
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。 -->
<setting name="aggressiveLazyLoading" value="true"/>
<!-- 是否允许单条sql 返回多个数据集 (取决于驱动的兼容性) default:true -->
<setting name="multipleResultSetsEnabled" value="true"/>
<!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->
<setting name="useColumnLabel" value="true"/>
<!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。 default:false -->
<setting name="useGeneratedKeys" value="false"/>
<!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分 FULL:全部 -->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!-- 这是默认的执行类型 (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新) -->
<setting name="defaultExecutorType" value="SIMPLE"/>
<!-- 使用驼峰命名法转换字段。
<setting name="mapUnderscoreToCamelCase" value="true"/>
-->
<!-- 设置本地缓存范围 session:就会有数据的共享 statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
<setting name="localCacheScope" value="SESSION"/>
<!-- 设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型 -->
<setting name="jdbcTypeForNull" value="NULL"/>
<!-- mybatis打印日志 -->
<!-- <setting name="logImpl" value="STDOUT_LOGGING" /> -->
<setting name="logImpl" value="NO_LOGGING" />
</settings> <!-- 类型别名 -->
<typeAliases>
</typeAliases> </configuration>

  4.jdbc.properties和log4j.properties

  这里我用的是oracle,在mac上用docker起了两个oracle数据库镜像,端口分别映射到本地mac的1521和1522,并且各自建了apple账号。

# docker ps --> oracle11g
oracle11g.driverClass=oracle.jdbc.driver.OracleDriver
oracle11g.url=jdbc:oracle:thin:@127.0.0.1:1521:helowin
oracle11g.username=apple
oracle11g.password=1234
oracle11g.maxActive=100
oracle11g.maxIdle=40
oracle11g.maxWait=3000
oracle11g.defaultAutoCommit=true
oracle11g.timeBetweenEvictionRunsMillis=3600000
oracle11g.minEvictableIdleTimeMillis=3600000 # docker ps --> oracle11g-1
oracle11g-1.driverClass=oracle.jdbc.driver.OracleDriver
oracle11g-1.url=jdbc:oracle:thin:@127.0.0.1:1522:helowin
oracle11g-1.username=apple
oracle11g-1.password=1234
oracle11g-1.maxActive=100
oracle11g-1.maxIdle=40
oracle11g-1.maxWait=3000
oracle11g-1.defaultAutoCommit=true
oracle11g-1.timeBetweenEvictionRunsMillis=3600000
oracle11g-1.minEvictableIdleTimeMillis=3600000
log4j.rootCategory=info, CONSOLE, DAILY
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-5p[%F:%M:%L]- %m%n
log4j.appender.DAILY=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DAILY.DatePattern='.'yyyy-MM-dd
log4j.appender.DAILY.ImmediateFlush=true
log4j.appender.DAILY.Append=true
log4j.appender.DAILY.layout=org.apache.log4j.PatternLayout
log4j.appender.DAILY.layout.conversionPattern=[ %-5p]-%-d{yyyyMMdd HHmmss}-[%F:%M:%L]- %m%n
log4j.appender.DAILY.File=../logs/mvc.log

  5.springmvc.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<mvc:annotation-driven>
<!-- 解决乱码 -->
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 设置注解扫描目录
注意,在springmvc-servlet中排除了@Service注解,它等价于在applicationContext.xml中排除@Controller注解
SpringMVC中扫描controller而不是@Service,因为此时service还没有进行事务处理可能会引起事务失效
-->
<context:component-scan base-package="com.mvc" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan> <!-- 静态资源访问控制 -->
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/js/**" location="/js/" />
<mvc:resources mapping="/css/**" location="/css/" />
</beans>

springmvc.xml

  6.web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0"
> <display-name>Archetype Created Web Application</display-name>
<!-- 注册ApplicationContext容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <!--注册中央调度器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>welcome.jsp</welcome-file>
</welcome-file-list> <!--解决requesMapping请求参数中的中文乱码-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

web.xml

二、自定义类

  1.DataSource

package com.mvc.dynamicDataSource;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target({ ElementType.TYPE,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default DataSource.dataSource1;
public static String dataSource1 = "dataSource1";
public static String dataSource2 = "dataSource2";
}

  2.DataSourceAspect

package com.mvc.dynamicDataSource;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; @Component
@Aspect
@Order(1)
public class dataSourceAspect { @Pointcut(value="execution(* com.mvc.laboratory..*.*(..))")
private void doPointcut() {}; @Before(value = "doPointcut()")
@After(value = "doPointcut()")
public void intercept(JoinPoint joinPoint) throws NoSuchMethodException {
// 获取切入点的类反射
Class<?> targetClass = joinPoint.getTarget().getClass();
// 获取方法参数
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
for (Class<?> clazz:targetClass.getInterfaces()){
dealDataSource(clazz, signature.getMethod());
}
// 默认使用目标类的注解,如果没有则使用其实现的接口注解
dealDataSource(targetClass, signature.getMethod());
} private void dealDataSource(Class<?> clazz, Method method) throws NoSuchMethodException {
// 获取方法参数
Class<?>[] paramTypeArr = method.getParameterTypes();
// 检查是否为dataSource注解
if (clazz.isAnnotationPresent(DataSource.class)){
// 获取注解对象
DataSource source = clazz.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.value());
}
Method m = clazz.getMethod(method.getName(), paramTypeArr);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.value());
}
}
}

  3.DynamicDataSource

package com.mvc.dynamicDataSource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
* 通过重写这个查找数据源标识的方法就可以让spring切换到指定的数据源 *
*/
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
// 从自定义的位置获取数据源标识
return DynamicDataSourceHolder.getDataSource();
}
}

  4.DynamicDataSourceHolder

package com.mvc.dynamicDataSource;

/**
* 用于持有当前线程中使用的数据源标识
*/
public class DynamicDataSourceHolder {
// 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰
private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<>(); public static String getDataSource() {
return THREAD_DATA_SOURCE.get();
}
public static void setDataSource(String dataSource) {
THREAD_DATA_SOURCE.set(dataSource);
}
public static void clearDataSource() {
THREAD_DATA_SOURCE.remove();
}
}

三、业务代码

  1.TestController

package com.mvc.laboratory.test;

import java.util.List;
import java.util.Map; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
@RequestMapping(value = "/test")
public class TestController { @Resource
private TestService testService; /**
* @see http://localhost:8080/mvclab/test/testAspectJAround?name=weiweian&age=123
* @param name
* @param age
* @return
*/
@RequestMapping(value = "/testAspectJAround")
@ResponseBody
public List<Map<String, String>> testAspectJArounds(HttpServletRequest request, String name, String age){
List<Map<String, String>> map = testService.testAspectJAround(request, name, age);
return map;
}
/**
* @see http://localhost:8080/mvclab/test/testDynamicDataSource
* @param request
* @return
*/
@RequestMapping(value = "/testDynamicDataSource")
@ResponseBody
public List<Map<String, String>> testDynamicDataSource(HttpServletRequest request){
List<Map<String, String>> map = testService.testDynamicDataSource(request);
return map;
}
}

  2.TestService

package com.mvc.laboratory.test;

import java.util.List;
import java.util.Map; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; @Service
@Transactional(rollbackFor = Exception.class)
public class TestService { @Resource
private LoggerDao loggerDao;
@Resource
private TestDao testDao; public List<Map<String, String>> testAspectJAround(HttpServletRequest request, String name, String age) {
List<Map<String, String>> map = loggerDao.test();
return map;
} public List<Map<String, String>> testDynamicDataSource(HttpServletRequest request) {
List<Map<String, String>> map = testDao.dynamicDataSource();
return map;
}
}

  3.LoggerDao

package com.mvc.laboratory.test;

import java.util.Date;
import java.util.List;
import java.util.Map; import org.apache.ibatis.annotations.Param; import com.mvc.dynamicDataSource.DataSource; @DataSource(DataSource.dataSource1)
public interface LoggerDao {
public List<Map<String, String>> test();
}

  4.TestDao

package com.mvc.laboratory.test;

import java.util.List;
import java.util.Map; import com.mvc.dynamicDataSource.DataSource; @DataSource(DataSource.dataSource2)
public interface TestDao {
public List<Map<String, String>> dynamicDataSource();
}

  5.logger.xml和test.xml

  参考applicationcontext.xml中关于mabatis的配置,目录为resources/mappings/test/logger.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mvc.laboratory.test.LoggerDao"> <select id="test" resultType="java.util.Map">
        select
            url,
            intfname,
            sign,
            to_char(begin_time) as begin_time,
            to_char(end_time) as end_time,
            result
         from intf_caller_log
</select> </mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mvc.laboratory.test.TestDao"> <select id="dynamicDataSource" resultType="java.util.Map">
select * from test
</select> </mapper>

  6.intf_caller_log和test表

  参考LoggerDao的注解,intf_caller_log表位于dataSource1数据源对应的数据库中,test表位于dataSource2数据源对应的数据库中,两个表只是查询,可自由创建。

四、测试

  1.单元测试

  在test/mvc路径下新建测试类,内容如下:

package mvc;

import java.util.List;
import java.util.Map; import javax.annotation.Resource; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional; import com.mvc.laboratory.test.LoggerDao;
import com.mvc.laboratory.test.TestDao; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
@Transactional(rollbackFor = Exception.class)
public class DynamicDataSourceTest { @Resource
private LoggerDao loggerDao; @Resource
private TestDao testDao; @Test
public void loggerTest() {
List<Map<String, String>> map = loggerDao.test();
for (int i = 0; i < map.size(); i++) {
System.out.println(map.get(i));
}
} @Test
public void dynamicDataSourceTest() {
List<Map<String, String>> map = testDao.dynamicDataSource();
for (int i = 0; i < map.size(); i++) {
System.out.println(map.get(i));
}
}
}

  分别执行两个方法(run as junit,可在run configuration中配置要执行的方法及junit版本(这里是4)),打印如下:

...
{INTFNAME=@82c0502, END_TIME=2019-06-26 09:44:04.0, BEGIN_TIME=2019-06-26 09:44:04.0, ID=8C312E309096C199E05011AC02001066, SIGN=1, RESULT={sayHello=hello, my name is weiweian, 123 years old., name=weiweian, age=123}, URL=/mvclab/test/example1}
{INTFNAME=@784a89d9, END_TIME=2019-06-26 10:09:43.0, BEGIN_TIME=2019-06-26 10:09:43.0, ID=8C3189ED0639F220E05011AC0200107C, SIGN=1, RESULT={sayHello=hello, my name is weiweian, 123 years old., name=weiweian, age=123}, URL=/mvclab/test/testAspectJAround}
{INTFNAME=@349f84fe, END_TIME=2019-06-26 10:40:22.0, BEGIN_TIME=2019-06-26 10:40:22.0, ID=8C31F7934D601BCFE05011AC02001092, SIGN=1, RESULT={sayHello=hello, my name is weiweian, 123 years old., name=weiweian, age=123}, URL=/mvclab/test/testAspectJAround}
...
...
{ID=8C31D356D681E364E05011AC03000F08, NAME=Alex, AGE=20}
{ID=8C31D356D682E364E05011AC03000F08, NAME=An, AGE=18}
...

  可见,intf_caller_log表中的记录和test表中的记录都能正常查询出来。查询其它表也应该是相应的数据。

  2.发布到tomcat测试

  分别访问controller中的测试路径,页面显示如下:

[
{
"INTFNAME": "@3507200d",
"END_TIME": "26-6月 -19",
"BEGIN_TIME": "26-6月 -19",
"SIGN": "1",
"RESULT": "{sayHello=hello, my name is weiweian, 123 years old., name=weiweian, age=123}",
"URL": "/mvclab/test/testAspectJAround"
},
{
"INTFNAME": "@3507200d",
"END_TIME": "26-6月 -19",
"BEGIN_TIME": "26-6月 -19",
"SIGN": "1",
"RESULT": "{sayHello=hello, my name is weiweian, 123 years old., name=weiweian, age=123}",
"URL": "/mvclab/test/testAspectJAround"
},
...
[
{
"ID": "8C31D356D681E364E05011AC03000F08",
"NAME": "Alex",
"AGE": "20"
},
{
"ID": "8C31D356D682E364E05011AC03000F08",
"NAME": "An",
"AGE": "18"
}
]

五、Hibernate事务管理配置多数据源

  只修改pom.xml添加相关jar包,以及application.xml添加Hibernate事务管理,其它和上述一样不变。

  1.pom.xml

  添加hibernate相关jar包

<project xmlns="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.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>laboratory</groupId>
<artifactId>mvclab</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>mcv Maven Webapp</name>
<url>http://maven.apache.org</url> <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>
<spring.version>5.1.5.RELEASE</spring.version>
<mybatis.version>3.2.8</mybatis.version>
<mybatis-spring.version>1.2.2</mybatis-spring.version>
<spring-jpa-version>1.3.2.RELEASE</spring-jpa-version>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency> <!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency> <!--tomcat所需jar包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency> <dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<!-- Spring JPA dependencies -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-jpa-version}</version>
</dependency> <!-- Hibernate dependencies -->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.0-api -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency> <!--返回object对象所需要的依赖,它在<mvc:annotation-driven>注册时注入-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency> <!-- 补充 -->
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency> <!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- dbcp数据源 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>mcv</finalName>
</build>
</project>

  2.applicationContext.xml

  注释掉jdbc事务管理,添加hibernate事务管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- context:设置注解扫描包注解
注: 如果springmvc-servlet中扫描注解没有排除@Service注解,这里要设置扫描除@Controller之外的其它所有注解
-->
<context:component-scan base-package="com.mvc">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<!-- 自定义异常处理 -->
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan> <!-- 开启@Autowired注解扫描
注: 它等价于<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/>
注: 配置了<context:component-scan />,默认包含对@Autowired的配置,因此下面这个配置就不需要了
-->
<context:annotation-config/> <!-- 注册数据源配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 注册数据源对象 这里用Spring内置数据源 -->
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>${oracle11g.driverClass}</value>
</property>
<property name="url">
<value>${oracle11g.url}</value>
</property>
<property name="username">
<value>${oracle11g.username}</value>
</property>
<property name="password">
<value>${oracle11g.password}</value>
</property>
<property name="maxActive">
<value>${oracle11g.maxActive}</value>
</property>
<property name="maxIdle">
<value>${oracle11g.maxIdle}</value>
</property>
<property name="maxWait">
<value>${oracle11g.maxWait}</value>
</property>
<property name="defaultAutoCommit">
<value>${oracle11g.defaultAutoCommit}</value>
</property>
<property name="timeBetweenEvictionRunsMillis">
<value>${oracle11g.timeBetweenEvictionRunsMillis}</value>
</property>
<property name="minEvictableIdleTimeMillis">
<value>${oracle11g.minEvictableIdleTimeMillis}</value>
</property>
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>${oracle11g-1.driverClass}</value>
</property>
<property name="url">
<value>${oracle11g-1.url}</value>
</property>
<property name="username">
<value>${oracle11g-1.username}</value>
</property>
<property name="password">
<value>${oracle11g-1.password}</value>
</property>
<property name="maxActive">
<value>${oracle11g-1.maxActive}</value>
</property>
<property name="maxIdle">
<value>${oracle11g-1.maxIdle}</value>
</property>
<property name="maxWait">
<value>${oracle11g-1.maxWait}</value>
</property>
<property name="defaultAutoCommit">
<value>${oracle11g-1.defaultAutoCommit}</value>
</property>
<property name="timeBetweenEvictionRunsMillis">
<value>${oracle11g-1.timeBetweenEvictionRunsMillis}</value>
</property>
<property name="minEvictableIdleTimeMillis">
<value>${oracle11g-1.minEvictableIdleTimeMillis}</value>
</property>
</bean>
<!-- 配置动态数据源 -->
<bean id="dynamicDataSource" class="com.mvc.dynamicDataSource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- 指定lookupKey和与之对应的数据源 -->
<entry key="dataSource1" value-ref="dataSource1" />
<entry key="dataSource2" value-ref="dataSource2" />
</map>
</property>
<!-- 指定默认的数据源 -->
<property name="defaultTargetDataSource" ref="dataSource1" />
</bean> <!-- 配置事务管理对象-->
<!--
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource1" />
</bean>
--> <!-- Hibernate JPA vendor adapter -->
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
</bean>
<!-- JPA entity manager factory -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource1"/>
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
<property name="packagesToScan" value="com.mvc.laboratory"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<!-- JPA transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean> <!-- 将所有具有@Transactional注解的Bean自动配置为声明式事务支持 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> <!-- MyBatis 数据源和sql- -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
<property name="mapperLocations" value="classpath:/mappings/**/*.xml"/>
<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
</bean>
<!-- MyBayis 扫描器配置-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.mvc.laboratory"/>
</bean> <!--接收json数据-->
<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean> <!-- 配置事务自动代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
</beans>

  同样进行单元测试,动态数据源切换可照常使用。

  

SSM配置动态数据源的更多相关文章

  1. 如何通过Spring Boot配置动态数据源访问多个数据库

    之前写过一篇博客<Spring+Mybatis+Mysql搭建分布式数据库访问框架>描述如何通过Spring+Mybatis配置动态数据源访问多个数据库.但是之前的方案有一些限制(原博客中 ...

  2. SpringBoot整合MyBatisPlus配置动态数据源

    目录 SpringBoot整合MyBatisPlus配置动态数据源 SpringBoot整合MyBatisPlus配置动态数据源 推文:2018开源中国最受欢迎的中国软件MyBatis-Plus My ...

  3. SSH配置动态数据源

    用到一个项目,需要整合2个不同的数据库! 现将代码贴下,以备后用: 1.创建静态映射类,该类映射动态数据源 public class DataSourceMap { public static fin ...

  4. Spring配置动态数据源-读写分离和多数据源

    在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...

  5. 使用Spring配置动态数据源实现读写分离

    最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考.关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!-- ...

  6. SpringBoot集成Mybatis配置动态数据源

    很多人在项目里边都会用到多个数据源,下面记录一次SpringBoot集成Mybatis配置多数据源的过程. pom.xml <?xml version="1.0" encod ...

  7. 使用 Spring 配置动态数据源实现读写分离

    关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!--读数据源配置--><bean id="readData ...

  8. 阿里P7教你如何使用 Spring 配置动态数据源实现读写分离

    最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考. 关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!- ...

  9. Spring-Boot 多数据源配置+动态数据源切换+多数据源事物配置实现主从数据库存储分离

    一.基础介绍 多数据源字面意思,比如说二个数据库,甚至不同类型的数据库.在用SpringBoot开发项目时,随着业务量的扩大,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源. ...

随机推荐

  1. 【转】ASP.NET Core 如何设置发布环境

    在ASP.NET Core中自带了一些内置对象,可以读取到当前程序处于什么样的环境当中,比如在ASP.NET Core的Startup类的Configure方法中,我们就会看到这么一段代码: publ ...

  2. 制作windows安装包的工具

    https://nsis.sourceforge.io/Download https://www.installaware.com/ https://www.advancedinstaller.com ...

  3. wpf dual monitor

    <Window x:Class="DualMonitors.Views.WinLeft" xmlns="http://schemas.microsoft.com/w ...

  4. qt 界面去掉系统边框

    该代码在Qt5框架编辑,使用该类时, 直接继承这个类就可以了. 实现了拖拽功能和关闭功能,如果需要放大缩小功能, 需自己实现. 1 #ifndef CUSTOMIZE_QWIDGET_H #defin ...

  5. Abp vNext框架 从空项目开始 使用ASP.NET Core Web Application-笔记

    参考 Abp vNext框架 从空项目开始 使用ASP.NET Core Web Application http://www.vnfan.com/helinbin/d/745b1e040c9b4f6 ...

  6. SQL server已经设置为单用户模式,还是无法做分离、属性设置等操作

    https://www.cnblogs.com/xingyunqiu/p/10336938.html SQL server已经设置为单用户模式,Sql server还原失败数据库正在使用,无法获得对数 ...

  7. Implement Custom Business Classes and Reference Properties 实现自定义业务类和引用属性(XPO)

    In this lesson, you will learn how to implement business classes from scratch. For this purpose, the ...

  8. 性能篇系列—stream详解

    Stream API Java 8集合中的Stream相当于高级版的Iterator Stream API通过Lambda表达式对集合进行各种非常便利高效的聚合操作,或者大批量数据操作 Stream的 ...

  9. RiscV汇编介绍(1)-编译过程

    从c/c++源文件,到可以执行文件,需要以下几个步骤: 预处理/编译 汇编 链接 下面我们以hello world程序为例,展示整个编译链接过程. 1. 编写hello.c代码 #include &l ...

  10. CVE-2019-0708-BlueKeep漏洞复现

    环境 攻击机:Kali Linux IP:192.168.0.108 靶机:Windows Sever 7 SP1 旗舰版 IP:192.168.0.109 Exploit: https://gith ...