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
相關文章
相關標籤/搜索