java框架之SpringBoot(9)-数据访问及整合MyBatis

简介

对于数据访问层,不管是 SQL 仍是 NOSQL,SpringBoot 默认采用整合 SpringData 的方式进行统一处理,添加了大量的自动配置,引入了各类 Template、Repository 来简化咱们对数据访问层的操做,咱们使用时只需进行简单的配置便可。css

整合JDBC

数据源获取

一、使用 maven 构建 SpringBoot 项目,引入以下场景启动器:java

二、配置数据库链接相关信息:mysql

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.202.135:3306/springboot_jdbc
    driver-class-name: com.mysql.jdbc.Driver
application.yml

三、作完上述两个操做咱们就能够直接测试获取数据源了:web

package com.springboot.data_jdbc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DataJdbcApplicationTests {
    @Autowired
    public DataSource dataSource;

    @Test
    public void testDataSource() throws SQLException {
        System.out.println(dataSource);
        System.out.println(dataSource.getClass());
        /*
        org.apache.tomcat.jdbc.pool.DataSource@6107165{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100;...}
        class org.apache.tomcat.jdbc.pool.DataSource
         */
    }
}
test

操做数据库

SpringBoot 经过 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration 自动配置类为咱们自动配置了 JdbcTemplate,因此能够直接从容器中获取使用它。spring

package com.springboot.data_jdbc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DataJdbcApplicationTests {
    @Autowired
    public JdbcTemplate jdbcTemplate;

    @Test
    public void testJdbcTemplate() throws SQLException {
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from user;");
        System.out.println(maps);
        /*
        [{id=1, name=张三}]
         */
    }
}

源码分析

上述使用中咱们只是在配置文件中配置了数据库链接信息而后咱们就能够直接获取到数据源,缘由也是由于 SpringBoot 给咱们作了大量的自动配置,对应的相关自动配置类在 org.springframework.boot.autoconfigure.jdbc 包下:sql

查看 DataSourceConfiguration 类:数据库

 1 abstract class DataSourceConfiguration {
 2 
 3     @SuppressWarnings("unchecked")
 4     protected static <T> T createDataSource(DataSourceProperties properties,
 5             Class<? extends DataSource> type) {
 6         return (T) properties.initializeDataSourceBuilder().type(type).build();
 7     }
 8 
 9     @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
10     @ConditionalOnMissingBean(DataSource.class)
11     @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
12     static class Tomcat {
13 
14         @Bean
15         @ConfigurationProperties(prefix = "spring.datasource.tomcat")
16         public org.apache.tomcat.jdbc.pool.DataSource dataSource(
17                 DataSourceProperties properties) {
18             org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(
19                     properties, org.apache.tomcat.jdbc.pool.DataSource.class);
20             DatabaseDriver databaseDriver = DatabaseDriver
21                     .fromJdbcUrl(properties.determineUrl());
22             String validationQuery = databaseDriver.getValidationQuery();
23             if (validationQuery != null) {
24                 dataSource.setTestOnBorrow(true);
25                 dataSource.setValidationQuery(validationQuery);
26             }
27             return dataSource;
28         }
29 
30     }
31 
32     @ConditionalOnClass(HikariDataSource.class)
33     @ConditionalOnMissingBean(DataSource.class)
34     @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
35     static class Hikari {
36 
37         @Bean
38         @ConfigurationProperties(prefix = "spring.datasource.hikari")
39         public HikariDataSource dataSource(DataSourceProperties properties) {
40             return createDataSource(properties, HikariDataSource.class);
41         }
42 
43     }
44 
45     @ConditionalOnClass(org.apache.commons.dbcp.BasicDataSource.class)
46     @ConditionalOnMissingBean(DataSource.class)
47     @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp.BasicDataSource", matchIfMissing = true)
48     @Deprecated
49     static class Dbcp {
50 
51         @Bean
52         @ConfigurationProperties(prefix = "spring.datasource.dbcp")
53         public org.apache.commons.dbcp.BasicDataSource dataSource(
54                 DataSourceProperties properties) {
55             org.apache.commons.dbcp.BasicDataSource dataSource = createDataSource(
56                     properties, org.apache.commons.dbcp.BasicDataSource.class);
57             DatabaseDriver databaseDriver = DatabaseDriver
58                     .fromJdbcUrl(properties.determineUrl());
59             String validationQuery = databaseDriver.getValidationQuery();
60             if (validationQuery != null) {
61                 dataSource.setTestOnBorrow(true);
62                 dataSource.setValidationQuery(validationQuery);
63             }
64             return dataSource;
65         }
66 
67     }
68 
69     @ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
70     @ConditionalOnMissingBean(DataSource.class)
71     @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true)
72     static class Dbcp2 {
73 
74         @Bean
75         @ConfigurationProperties(prefix = "spring.datasource.dbcp2")
76         public org.apache.commons.dbcp2.BasicDataSource dataSource(
77                 DataSourceProperties properties) {
78             return createDataSource(properties,
79                     org.apache.commons.dbcp2.BasicDataSource.class);
80         }
81 
82     }
83 
84     @ConditionalOnMissingBean(DataSource.class)
85     @ConditionalOnProperty(name = "spring.datasource.type")
86     static class Generic {
87 
88         @Bean
89         public DataSource dataSource(DataSourceProperties properties) {
90             return properties.initializeDataSourceBuilder().build();
91         }
92 
93     }
94 }
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration

能够看到在当前工程引入不一样数据源依赖时 SpringBoot 会给咱们自动注册不一样类型的数据源 bean,默认提供以下几个数据源的自动配置:apache

org.apache.tomcat.jdbc.pool.DataSource # 因 web 场景启动器默认引入了 tomcat 依赖,因此默认使用该数据源
com.zaxxer.hikari.HikariDataSource
org.apache.commons.dbcp.BasicDataSource
org.apache.commons.dbcp2.BasicDataSource

除了上面几个可自动配置的数据源,在第 86-93 行还有一个 Generic 内部类,该内部类的做用是为咱们提供定制其它数据源功能的支持。它是如何让咱们实现自定义数据源的呢?tomcat

首先该内部类起做用的前提是咱们在 IoC 容器中没有注册数据源,而且还在配置中经过 spring.datasource.type 指定了数据源类型。知足这两个条件后才会作以下操做:springboot

dataSource 方法是用来想容器中注册一个数据源 bean,而这个 bean 的是由第 90 行经过 properties.initializeDataSourceBuilder() 初始化的一个数据源构建器的 build() 生成的,查看该方法:

1 public DataSourceBuilder initializeDataSourceBuilder() {
2     return DataSourceBuilder.create(getClassLoader()).type(getType())
3             .driverClassName(determineDriverClassName()).url(determineUrl())
4             .username(determineUsername()).password(determinePassword());
5 }
org.springframework.boot.autoconfigure.jdbc.DataSourceProperties#initializeDataSourceBuilder

该方法建立了一个数据源构建器,接着将数据库链接信息绑定到该构建器,而这些数据库链接信息的值正是咱们在配置文件中配置的 spring.datasource 节下的属性值,最后返回该构建器的实例,接着调用该构建器的 build() 方法:

1 public DataSource build() {
2     Class<? extends DataSource> type = getType();
3     DataSource result = BeanUtils.instantiate(type);
4     maybeGetDriverClassName();
5     bind(result);
6     return result;
7 }
org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder#build

最终利用反射建立对应类型数据源的实例,绑定数据库链接信息,返回了数据源。

再查看 DataSourceAutoConfiguration 类:

  1 @Configuration
  2 @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
  3 @EnableConfigurationProperties(DataSourceProperties.class)
  4 @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
  5 public class DataSourceAutoConfiguration {
  6 
  7     private static final Log logger = LogFactory
  8             .getLog(DataSourceAutoConfiguration.class);
  9 
 10     @Bean
 11     @ConditionalOnMissingBean
 12     public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
 13             ApplicationContext applicationContext) {
 14         return new DataSourceInitializer(properties, applicationContext);
 15     }
 16 
 17     public static boolean containsAutoConfiguredDataSource(
 18             ConfigurableListableBeanFactory beanFactory) {
 19         try {
 20             BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dataSource");
 21             return EmbeddedDataSourceConfiguration.class.getName()
 22                     .equals(beanDefinition.getFactoryBeanName());
 23         }
 24         catch (NoSuchBeanDefinitionException ex) {
 25             return false;
 26         }
 27     }
 28 
 29     @Configuration
 30     @Conditional(EmbeddedDatabaseCondition.class)
 31     @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
 32     @Import(EmbeddedDataSourceConfiguration.class)
 33     protected static class EmbeddedDatabaseConfiguration {
 34 
 35     }
 36 
 37     @Configuration
 38     @Conditional(PooledDataSourceCondition.class)
 39     @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
 40     @Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class,
 41             DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class,
 42             DataSourceConfiguration.Generic.class })
 43     @SuppressWarnings("deprecation")
 44     protected static class PooledDataSourceConfiguration {
 45 
 46     }
 47 
 48     @Configuration
 49     @ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled")
 50     @ConditionalOnClass(name = "org.apache.tomcat.jdbc.pool.DataSourceProxy")
 51     @Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)
 52     @ConditionalOnMissingBean(name = "dataSourceMBean")
 53     protected static class TomcatDataSourceJmxConfiguration {
 54 
 55         @Bean
 56         public Object dataSourceMBean(DataSource dataSource) {
 57             if (dataSource instanceof DataSourceProxy) {
 58                 try {
 59                     return ((DataSourceProxy) dataSource).createPool().getJmxPool();
 60                 }
 61                 catch (SQLException ex) {
 62                     logger.warn("Cannot expose DataSource to JMX (could not connect)");
 63                 }
 64             }
 65             return null;
 66         }
 67 
 68     }
 69 
 70     static class PooledDataSourceCondition extends AnyNestedCondition {
 71 
 72         PooledDataSourceCondition() {
 73             super(ConfigurationPhase.PARSE_CONFIGURATION);
 74         }
 75 
 76         @ConditionalOnProperty(prefix = "spring.datasource", name = "type")
 77         static class ExplicitType {
 78 
 79         }
 80 
 81         @Conditional(PooledDataSourceAvailableCondition.class)
 82         static class PooledDataSourceAvailable {
 83 
 84         }
 85 
 86     }
 87 
 88     static class PooledDataSourceAvailableCondition extends SpringBootCondition {
 89 
 90         @Override
 91         public ConditionOutcome getMatchOutcome(ConditionContext context,
 92                 AnnotatedTypeMetadata metadata) {
 93             ConditionMessage.Builder message = ConditionMessage
 94                     .forCondition("PooledDataSource");
 95             if (getDataSourceClassLoader(context) != null) {
 96                 return ConditionOutcome
 97                         .match(message.foundExactly("supported DataSource"));
 98             }
 99             return ConditionOutcome
100                     .noMatch(message.didNotFind("supported DataSource").atAll());
101         }
102 
103         private ClassLoader getDataSourceClassLoader(ConditionContext context) {
104             Class<?> dataSourceClass = new DataSourceBuilder(context.getClassLoader())
105                     .findType();
106             return (dataSourceClass != null) ? dataSourceClass.getClassLoader() : null;
107         }
108 
109     }
110 
111     static class EmbeddedDatabaseCondition extends SpringBootCondition {
112 
113         private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();
114 
115         @Override
116         public ConditionOutcome getMatchOutcome(ConditionContext context,
117                 AnnotatedTypeMetadata metadata) {
118             ConditionMessage.Builder message = ConditionMessage
119                     .forCondition("EmbeddedDataSource");
120             if (anyMatches(context, metadata, this.pooledCondition)) {
121                 return ConditionOutcome
122                         .noMatch(message.foundExactly("supported pooled data source"));
123             }
124             EmbeddedDatabaseType type = EmbeddedDatabaseConnection
125                     .get(context.getClassLoader()).getType();
126             if (type == null) {
127                 return ConditionOutcome
128                         .noMatch(message.didNotFind("embedded database").atAll());
129             }
130             return ConditionOutcome.match(message.found("embedded database").items(type));
131         }
132 
133     }
134 
135     @Order(Ordered.LOWEST_PRECEDENCE - 10)
136     static class DataSourceAvailableCondition extends SpringBootCondition {
137 
138         private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();
139 
140         private final SpringBootCondition embeddedCondition = new EmbeddedDatabaseCondition();
141 
142         @Override
143         public ConditionOutcome getMatchOutcome(ConditionContext context,
144                 AnnotatedTypeMetadata metadata) {
145             ConditionMessage.Builder message = ConditionMessage
146                     .forCondition("DataSourceAvailable");
147             if (hasBean(context, DataSource.class)
148                     || hasBean(context, XADataSource.class)) {
149                 return ConditionOutcome
150                         .match(message.foundExactly("existing data source bean"));
151             }
152             if (anyMatches(context, metadata, this.pooledCondition,
153                     this.embeddedCondition)) {
154                 return ConditionOutcome.match(message
155                         .foundExactly("existing auto-configured data source bean"));
156             }
157             return ConditionOutcome
158                     .noMatch(message.didNotFind("any existing data source bean").atAll());
159         }
160 
161         private boolean hasBean(ConditionContext context, Class<?> type) {
162             return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
163                     context.getBeanFactory(), type, true, false).length > 0;
164         }
165 
166     }
167 
168 }
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

看第 12 行, dataSourceInitializer() 方法给容器中注册了一个数据源初始化器,查看初始化器类:

  1 class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {
  2 
  3     private static final Log logger = LogFactory.getLog(DataSourceInitializer.class);
  4 
  5     private final DataSourceProperties properties;
  6 
  7     private final ApplicationContext applicationContext;
  8 
  9     private DataSource dataSource;
 10 
 11     private boolean initialized = false;
 12 
 13     DataSourceInitializer(DataSourceProperties properties,
 14             ApplicationContext applicationContext) {
 15         this.properties = properties;
 16         this.applicationContext = applicationContext;
 17     }
 18 
 19     @PostConstruct
 20     public void init() {
 21         if (!this.properties.isInitialize()) {
 22             logger.debug("Initialization disabled (not running DDL scripts)");
 23             return;
 24         }
 25         if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
 26                 false).length > 0) {
 27             this.dataSource = this.applicationContext.getBean(DataSource.class);
 28         }
 29         if (this.dataSource == null) {
 30             logger.debug("No DataSource found so not initializing");
 31             return;
 32         }
 33         runSchemaScripts();
 34     }
 35 
 36     private void runSchemaScripts() {
 37         List<Resource> scripts = getScripts("spring.datasource.schema",
 38                 this.properties.getSchema(), "schema");
 39         if (!scripts.isEmpty()) {
 40             String username = this.properties.getSchemaUsername();
 41             String password = this.properties.getSchemaPassword();
 42             runScripts(scripts, username, password);
 43             try {
 44                 this.applicationContext
 45                         .publishEvent(new DataSourceInitializedEvent(this.dataSource));
 46                 if (!this.initialized) {
 47                     runDataScripts();
 48                     this.initialized = true;
 49                 }
 50             }
 51             catch (IllegalStateException ex) {
 52                 logger.warn("Could not send event to complete DataSource initialization ("
 53                         + ex.getMessage() + ")");
 54             }
 55         }
 56     }
 57 
 58     @Override
 59     public void onApplicationEvent(DataSourceInitializedEvent event) {
 60         if (!this.properties.isInitialize()) {
 61             logger.debug("Initialization disabled (not running data scripts)");
 62             return;
 63         }
 64         if (!this.initialized) {
 65             runDataScripts();
 66             this.initialized = true;
 67         }
 68     }
 69 
 70     private void runDataScripts() {
 71         List<Resource> scripts = getScripts("spring.datasource.data",
 72                 this.properties.getData(), "data");
 73         String username = this.properties.getDataUsername();
 74         String password = this.properties.getDataPassword();
 75         runScripts(scripts, username, password);
 76     }
 77 
 78     private List<Resource> getScripts(String propertyName, List<String> resources,
 79             String fallback) {
 80         if (resources != null) {
 81             return getResources(propertyName, resources, true);
 82         }
 83         String platform = this.properties.getPlatform();
 84         List<String> fallbackResources = new ArrayList<String>();
 85         fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
 86         fallbackResources.add("classpath*:" + fallback + ".sql");
 87         return getResources(propertyName, fallbackResources, false);
 88     }
 89 
 90     private List<Resource> getResources(String propertyName, List<String> locations,
 91             boolean validate) {
 92         List<Resource> resources = new ArrayList<Resource>();
 93         for (String location : locations) {
 94             for (Resource resource : doGetResources(location)) {
 95                 if (resource.exists()) {
 96                     resources.add(resource);
 97                 }
 98                 else if (validate) {
 99                     throw new ResourceNotFoundException(propertyName, resource);
100                 }
101             }
102         }
103         return resources;
104     }
105 
106     private Resource[] doGetResources(String location) {
107         try {
108             SortedResourcesFactoryBean factory = new SortedResourcesFactoryBean(
109                     this.applicationContext, Collections.singletonList(location));
110             factory.afterPropertiesSet();
111             return factory.getObject();
112         }
113         catch (Exception ex) {
114             throw new IllegalStateException("Unable to load resources from " + location,
115                     ex);
116         }
117     }
118 
119     private void runScripts(List<Resource> resources, String username, String password) {
120         if (resources.isEmpty()) {
121             return;
122         }
123         ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
124         populator.setContinueOnError(this.properties.isContinueOnError());
125         populator.setSeparator(this.properties.getSeparator());
126         if (this.properties.getSqlScriptEncoding() != null) {
127             populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
128         }
129         for (Resource resource : resources) {
130             populator.addScript(resource);
131         }
132         DataSource dataSource = this.dataSource;
133         if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
134             dataSource = DataSourceBuilder.create(this.properties.getClassLoader())
135                     .driverClassName(this.properties.determineDriverClassName())
136                     .url(this.properties.determineUrl()).username(username)
137                     .password(password).build();
138         }
139         DatabasePopulatorUtils.execute(populator, dataSource);
140     }
141 
142 }
org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer

在第 20 行有一个初始化方法,该方法会在当前类实例建立完成以后执行,在第 33 行执行了 runSchemaScripts() 方法,这里直接说明该方法的做用,该方法是使用来执行指定位置存放的 sql 文件中的 DDL 语句。

接着在第 37 行经过 getScripts("spring.datasource.schema", this.properties.getSchema(), "schema") 方法获取一个 DDL 脚本资源列表。接着来到第 78 行的 getScripts 方法,若是咱们没有在配置文件中经过 spring.datasource.schema 属性指定 DDL sql 文件路径列表,那么将默认使用 classpath*:schema-all.sql 和 classpath*:schema.sql 位置的资源,即会执行该 sql 资源文件中的 DDL 语句。也能够经过配置 spring.datasource.schema 属性来指定一个存放有 DDL 语句的 sql 文件资源路径列表。

能够看到该类还实现了 ApplicationListener 监听器接口,即应用程序启动完成后会调用该类实例的 onApplicationEvent 方法,在该方法中执行了 runDataScripts() 方法,而该方法的做用是用来执行指定位置存放的 sql 文件中的 DML 语句。

接着在第 70 行的 runDataScripts() 方法中执行了 getScripts("spring.datasource.data", this.properties.getData(), "data") 来获取 DML 脚本资源列表,而后在第 71 行执行 getScripts("spring.datasource.data", this.properties.getData(), "data") 方法,与以前的 runSchemaScripts() 相似,若是咱们没有在配置文件中经过 spring.datasource.data 属性指定 DML sql 文件的路径列表,那么将默认使用 classpath*:data-all.sql 和 classpath*:data.sql 位置的资源,即会执行该 sql 资源文件中的 DML 语句。也能够经过配置 spring.datasource.data 属性指定 DML sql 文件路径列表。

总结:
  • 能够在项目的 classpath 下放置存放有 DDL 语句的 schema-all.sql 和 schema.sql sql 脚本文件,也能够经过配置 spring.datasource.schema 属性自定义 DDL 语句 sql 文件的存放路径列表,SpringBoot 将会在项目启动时执行这些文件。
  • 能够在项目的 classpath 下放置存放有 DML 语句的 data-all.sql 和 data.sql sql 脚本文件,也能够经过配置 spring.datasource.data 属性自定义 DML 语句 sql 文件的存放路径列表,SpringBoot 将会在项目启动时执行这些文件。
例:
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.202.135:3306/springboot_jdbc
    driver-class-name: com.mysql.jdbc.Driver
    schema:
      - classpath:myschema.sql
    data:
      - classpath:mydata.sql
application.yml
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
myschema.sql
insert into user(name) values('张三');
mydata.sql

项目启动时将会执行 myschema 建立 user 表,并会执行 mydata.sql 往 user 表中添加一条数据。

切换数据源为Druid

要引入 Druid 依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.15</version>
</dependency>

方式一:配置数据源类型

经过上面的源码分析咱们已经知道,若是咱们要切换数据源,只须要配置 spring.datasource.type 为指定的数据源类型便可,以下:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.202.135:3306/springboot_jdbc
    driver-class-name: com.mysql.jdbc.Driver
    schema:
      - classpath:myschema.sql
    data:
      - classpath:mydata.sql
    type: com.alibaba.druid.pool.DruidDataSource
application.yml

测试:

package com.springboot.data_jdbc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DataJdbcApplicationTests {
    @Autowired
    public DataSource dataSource;

    @Test
    public void testDataSource() throws SQLException {
        System.out.println(dataSource.getClass());
        /*
        class com.alibaba.druid.pool.DruidDataSource
         */
    }
}
test

方式二:手动注册数据源

方式一其实有一个弊端,若是咱们要使用 Druid 独有的配置,例如要配置 Druid 监控,仅仅在配置文件中是完成不了这个需求的,此时咱们就须要手动注册数据源,而且手动将配置的属性的绑定到数据源实例。

配置:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.202.135:3306/springboot_jdbc
    driver-class-name: com.mysql.jdbc.Driver
    # Durid 独有的属性
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 1 from DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    # 配置监控统计拦截的 filter ,去掉后监控界面没法统计,wall 用于防火墙
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
application.yml

手动注册数据源 bean 并配置监控:

package com.springboot.data_jdbc.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DuridConfig {

    @ConfigurationProperties("spring.datasource") // 手动绑定配置属性
    @Bean
    public DataSource duridDataSource(){
        return new DruidDataSource();
    }

    // 配置 Druid 监控
    // 一、配置一个管理后台的 Servlet
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        Map<String, String> initParams = new HashMap<>();
        initParams.put("loginUsername", "admin"); // 登陆后台的用户名
        initParams.put("loginPassword", "123456");
        initParams.put("allow",""); // 默认容许全部域名及 IP 访问
        initParams.put("deny","127.0.0.1"); // 拒绝 127.0.0.1 访问

        servletRegistrationBean.setInitParameters(initParams);

        return servletRegistrationBean;
    }
    // 二、配置一个监控的 filter
    @Bean
    public FilterRegistrationBean webStatFilter(){

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        WebStatFilter webStatFilter = new WebStatFilter();
        filterRegistrationBean.setFilter(webStatFilter);
        Map<String, String> initParams = new HashMap<>();

        initParams.put("exclusions", "*.js,*.css,/druid/*");

        filterRegistrationBean.setInitParameters(initParams);
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
        return filterRegistrationBean;
    }
}
com.springboot.data_jdbc.config.DuridConfig

测试:

package com.springboot.data_jdbc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DataJdbcApplicationTests {
    @Autowired
    public DataSource dataSource;

    @Test
    public void testDataSource() throws SQLException {
        System.out.println(dataSource.getClass());
        /*
        class com.alibaba.druid.pool.DruidDataSource
         */
    }
}
test

启动项目,可经过 localhost:8080/druid 访问到监控平台:

整合MyBatis

一、使用 maven 构建 SpringBoot 项目,引入以下场景启动器:

二、引入 Druid 依赖,配置 Druid 数据源,初始化测试表:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.202.135:3306/springboot_mybatis
    driver-class-name: com.mysql.jdbc.Driver
    # Durid 独有的属性
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 1 from DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    # 配置监控统计拦截的 filter ,去掉后监控界面没法统计,wall 用于防火墙
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
    schema:
      - classpath:sql/user-schema.sql
    data:
      - classpath:sql/user-data.sql
application.yml
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(40) DEFAULT NULL,
  `gender` int(11) DEFAULT NULL COMMENT '0:女 1:男',
  `birthday` date DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
sql/user-schema.sql
INSERT INTO `user` VALUES ('1', '张三', '1', '1997-02-23', '北京');
INSERT INTO `user` VALUES ('2', '李四', '0', '1998-02-03', '武汉');
INSERT INTO `user` VALUES ('3', '王五', '1', '1996-06-04', '上海');
sql/user-data.sql
package com.springboot.data_mybatis.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DuridConfig {

    @ConfigurationProperties("spring.datasource") // 手动绑定配置属性
    @Bean
    public DataSource duridDataSource(){
        return new DruidDataSource();
    }

    // 配置 Druid 监控
    // 一、配置一个管理后台的 Servlet
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        Map<String, String> initParams = new HashMap<>();
        initParams.put("loginUsername", "admin"); // 登陆后台的用户名
        initParams.put("loginPassword", "123456");
        initParams.put("allow",""); // 默认容许全部域名及 IP 访问
        initParams.put("deny","127.0.0.1"); // 拒绝 127.0.0.1 访问

        servletRegistrationBean.setInitParameters(initParams);

        return servletRegistrationBean;
    }
    // 二、配置一个监控的 filter
    @Bean
    public FilterRegistrationBean webStatFilter(){

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        WebStatFilter webStatFilter = new WebStatFilter();
        filterRegistrationBean.setFilter(webStatFilter);
        Map<String, String> initParams = new HashMap<>();

        initParams.put("exclusions", "*.js,*.css,/druid/*");

        filterRegistrationBean.setInitParameters(initParams);
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
        return filterRegistrationBean;
    }
}
com.springboot.data_mybatis.config.DuridConfig

三、建立与测试表对应的 JavaBean:

package com.springboot.data_mybatis.bean;

import java.util.Date;

public class User {
    private Integer id;
    private String name;
    private Integer gender;
    private Date birthday;
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
com.springboot.data_mybatis.bean.User

注解方式

编写 mapper 类,并在 mapper 类中经过注解绑定 sql:

package com.springboot.data_mybatis.mapper;

import com.springboot.data_mybatis.bean.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserMappper {
    @Select("select * from user")
    public List<User> getAll();

    @Select("select * from user where id=#{id}")
    public User getById(Integer id);

    @Delete("delete from user where id=#{id}")
    public Integer deleteById(Integer id);

    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into user(name,gender,birthday,address) values(#{name},#{gender},#{birthday},#{address})")
    public Integer add(User user);

    @Update("update user set name=#{name},gender=#{gender},birthday=#{birthday},address=#{address} where id=#{id}")
    public Integer update(User user);
}
com.springboot.data_mybatis.mapper.UserMappper

测试:

package com.springboot.data_mybatis;

import com.springboot.data_mybatis.bean.User;
import com.springboot.data_mybatis.mapper.UserMappper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
@SuppressWarnings("all")
public class DataMybatisApplicationTests {

    @Autowired
    private DataSource dataSource;
    @Test
    public void test() {
        System.out.println(dataSource.getClass());
    }

    @Autowired
    private UserMappper userMappper;

    @Test
    public void testGetAll(){
        List<User> all = userMappper.getAll();
        System.out.println(all);
        /*
        [User{id=1, name='张三'}, User{id=2, name='李四'}, User{id=3, name='王五'}]
         */
    }

    @Test
    public void testGetById(){
        User user = userMappper.getById(1);
        System.out.println(user);
        /*
        User{id=1, name='张三'}
         */
    }


    @Test
    public void testAdd() throws ParseException {
        User user = new User();
        user.setName("赵六");
        user.setGender(1);
        user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1998-2-2"));
        user.setAddress("南京");
        Integer count = userMappper.add(user);
        System.out.println(count);
        /*
        1
         */
    }

    @Test
    public void testUpdate(){
        User user = userMappper.getById(4);
        user.setGender(0);
        Integer count = userMappper.update(user);
        System.out.println(count);
        /*
        1
         */
    }

    @Test
    public void testDelete(){
        Integer count = userMappper.deleteById(4);
        System.out.println(count);
        /*
        1
         */
    }
}
test

示例中是在 mapper 类上添加了 @Mapper 注解用来标识所标注的类是一个 Mapper 类,还能够经过 @MapperScan 注解配置 mapper 类的包扫描:

@MapperScan("com.springboot.data_mybatis.mapper")

能够看到上述注解方式没有 MyBatis 的核心配置文件,若是须要自定制 MyBatis 的部分配置,SpringBoot 给咱们提供了 MyBatis 配置自定制类,咱们只须要设置好该类实例相关属性将其放入 IoC 容器便可生效:

package com.springboot.data_mybatis.config;

import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;


@org.springframework.context.annotation.Configuration
public class MyBatisConfig {
    @Bean
    public ConfigurationCustomizer configurationCustomizer(){
        return new ConfigurationCustomizer() {
            @Override
            public void customize(Configuration configuration) {
                // 启用驼峰命名,表字段 user_name 可映射到 userName                                                                                                              属性
                configuration.setMapUnderscoreToCamelCase(true);
            }
        };
    }
}
com.springboot.data_mybatis.config.MyBatisConfig

XML配置方式

添加 MyBatis 核心配置文件:

<?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>
        <!--启用驼峰命名,表字段 user_name 可映射到 userName -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>
mybatis/mybatis-config.xml

在 SpringBoot 配置文件中指定 MyBatis 核心配置文件和映射文件位置:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.202.135:3306/springboot_mybatis
    driver-class-name: com.mysql.jdbc.Driver
    # Durid 独有的属性
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 1 from DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    # 配置监控统计拦截的 filter ,去掉后监控界面没法统计,wall 用于防火墙
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#    schema:
#      - classpath:sql/user-schema.sql
#    data:
#      - classpath:sql/user-data.sql
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml
application.yml

编写 mapper 类:

package com.springboot.data_mybatis.mapper;

import com.springboot.data_mybatis.bean.User;

import java.util.List;

public interface UserMappper {
    public List<User> getAll();

    public User getById(Integer id);

    public Integer deleteById(Integer id);

    public Integer add(User user);

    public Integer update(User user);
}
com.springboot.data_mybatis.mapper.UserMappper

编写映射文件:

<?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.springboot.data_mybatis.mapper.UserMappper">
    <select id="getAll" resultType="com.springboot.data_mybatis.bean.User">
        select * from user
    </select>

    <select id="getById" parameterType="int" resultType="com.springboot.data_mybatis.bean.User">
        select * from user where id=#{id}
    </select>

    <delete id="deleteById" parameterType="int">
        delete from user where id=#{id}
    </delete>

    <insert id="add" parameterType="com.springboot.data_mybatis.bean.User" useGeneratedKeys="true" keyProperty="id">
        insert into user(name,gender,birthday,address) values(#{name},#{gender},#{birthday},#{address})
    </insert>

    <update id="update" parameterType="com.springboot.data_mybatis.bean.User">
        update user set name=#{name},gender=#{gender},birthday=#{birthday},address=#{address} where id=#{id}
    </update>
</mapper>
mybatis/mapper/UserMapper.xml

使用注解配置 mapper 类的包扫描:

package com.springboot.data_mybatis;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.springboot.data_mybatis.mapper")
public class DataMybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(DataMybatisApplication.class, args);
    }

}
com.springboot.data_mybatis.DataMybatisApplication

测试:

package com.springboot.data_mybatis;

import com.springboot.data_mybatis.bean.User;
import com.springboot.data_mybatis.mapper.UserMappper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
@SuppressWarnings("all")
public class DataMybatisApplicationTests {

    @Autowired
    private DataSource dataSource;
    @Test
    public void test() {
        System.out.println(dataSource.getClass());
    }

    @Autowired
    private UserMappper userMappper;

    @Test
    public void testGetAll(){
        List<User> all = userMappper.getAll();
        System.out.println(all);
        /*
        [User{id=1, name='张三'}, User{id=2, name='李四'}, User{id=3, name='王五'}]
         */
    }

    @Test
    public void testGetById(){
        User user = userMappper.getById(1);
        System.out.println(user);
        /*
        User{id=1, name='张三'}
         */
    }


    @Test
    public void testAdd() throws ParseException {
        User user = new User();
        user.setName("赵六");
        user.setGender(1);
        user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1998-2-2"));
        user.setAddress("南京");
        Integer count = userMappper.add(user);
        System.out.println(count);
        /*
        1
         */
    }

    @Test
    public void testUpdate(){
        User user = userMappper.getById(5);
        user.setGender(0);
        Integer count = userMappper.update(user);
        System.out.println(count);
        /*
        1
         */
    }

    @Test
    public void testDelete(){
        Integer count = userMappper.deleteById(5);
        System.out.println(count);
        /*
        1
         */
    }
}
test

整合JPA

一、使用 maven 构建 SpringBoot 项目,引入如下依赖:

二、配置数据源及 JPA:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.202.135:3306/springboot_jpa
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    # JPA 默认使用 Hibernate 做为实现,因此可使用 Hibernate 配置
    hibernate:
      # 更新或建立数据表
      ddl-auto: update
      # 输出执行的 sql
    show-sql: true
application.yml

三、编写一个用于和数据库表映射的 JavaBean 即实体类,并配置好映射关系:

package com.springboot.data_jpa.bean;

import javax.persistence.*;
import java.util.Date;

// 使用 JPA 注解配置映射关系
@Entity // 告诉 JPA 这是一个实体类
@Table(name = "user") // 指定与哪张数据表对应,若是省略默认表名为类名首字母小写
public class User {
    @Id // 标识该字段为主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "name",length = 40) // 指定与表中的哪一个字段对应
    private String name;
    @Column // 若是省略默认列名为属性名
    private Integer gender;
    @Column
    private Date birthday;
    @Column
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
com.springboot.data_jpa.bean.User

四、编写 Repository 接口来操做实体类对应的数据表:

package com.springboot.data_jpa.repository;

import com.springboot.data_jpa.bean.User;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * 第一个类型参数为要操做的实体类型
 * 第二个类型参数为实体对应的主键类型
 */
public interface UserRepository extends JpaRepository<User,Integer> {
}
com.springboot.data_jpa.repository.UserRepository

五、测试:

package com.springboot.data_jpa;

import com.springboot.data_jpa.bean.User;
import com.springboot.data_jpa.repository.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DataJpaApplicationTests {

    @Autowired
    private UserRepository userRepository;
    @Test
    public void test() {
        System.out.println(userRepository);
        /*
        org.springframework.data.jpa.repository.support.SimpleJpaRepository@b022551
         */
    }

    @Test
    public void testAdd() throws ParseException {
        User user = new User();
        user.setName("赵六");
        user.setGender(1);
        user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1998-2-2"));
        user.setAddress("南京");
        User u = userRepository.save(user);
        System.out.println(u);
        /*
        Hibernate: insert into user (address, birthday, gender, name) values (?, ?, ?, ?)
        User{id=4, name='赵六'}
         */
    }

    @Test
    public void testGetAll(){
        List<User> all = userRepository.findAll();
        System.out.println(all);
        /*
        Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.birthday as birthday3_0_, user0_.gender as gender4_0_, user0_.name as name5_0_ from user user0_
        [User{id=1, name='张三'}, User{id=2, name='李四'}, User{id=3, name='王五'}, User{id=4, name='赵六'}]
         */
    }

    @Test
    public void testGetById(){
        User user = userRepository.findOne(1);
        System.out.println(user);
        /*
        Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.gender as gender4_0_0_, user0_.name as name5_0_0_ from user user0_ where user0_.id=?
        User{id=1, name='张三'}
         */
    }

    @Test
    public void testUpdate(){
        User user = userRepository.findOne(4);
        user.setGender(1);
        // 有主键时修改 不然保存
        userRepository.save(user);
        /*
        Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.gender as gender4_0_0_, user0_.name as name5_0_0_ from user user0_ where user0_.id=?
        Hibernate: update user set address=?, birthday=?, gender=?, name=? where id=?
         */
    }

    @Test
    public void testDelete(){
        userRepository.delete(4);
        /*
        Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.gender as gender4_0_0_, user0_.name as name5_0_0_ from user user0_ where user0_.id=?
        Hibernate: delete from user where id=?
         */
    }

}
test
相关文章
相关标签/搜索