zoukankan      html  css  js  c++  java
  • 6、SpringBootWeb开发-整合数据

    一、整合JDBC

    1、新建web项目

      引入JDBC APImysql DriverSpring Web

    Springboot会自动帮我们导入以下启动器

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency> 

    2、编写yaml配置文件

    spring:
      datasource:
        username: root
        password: zhixi158
        url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
        driver-class-name: com.mysql.cj.jdbc.Driver
    

    测试数据库连接信息:

    @SpringBootTest
    class Springboot03DataApplicationTests {
    
        @Autowired
        DataSource dataSource;
    
        @Test
        void contextLoads() throws SQLException {
            // 查看默认数据源
            System.out.println(dataSource.getClass());
    
            // 检查数据库连接
            Connection conn = dataSource.getConnection();
            System.out.println(conn);
    
            // 关闭
            conn.close();
        }
    }
    

     可以看出 Spring Boot 2.2.5 默认使用HikariDataSource 数据源,而以前版本,如 Spring Boot 1.5 默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源;

     3、测试查询数据库

    编写controller类,使用一个类:JdbcTemplate 实现CRUD等操作

    package com.zhixi.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.List;
    
    /**
     * @author zhangzhixi
     */
    @Controller
    public class JDBCController {
        @Autowired
        JdbcTemplate jdbcTemplate;
    
        /**
         * 添加用户
         */
        @ResponseBody
        @RequestMapping("/userAdd")
        public String addUser() {
            String sql = "insert into mybatis.user(id,name,pwd) values(6,'小六','666')";
            jdbcTemplate.update(sql);
            return "update ok!";
        }
    
        /**
         * 删除用户
         */
        @ResponseBody
        @RequestMapping("/delUser/{userId}")
        public String delUser(@PathVariable("userId") int userId) {
            String sql = "delete from mybatis.user where id = " + userId + "";
            jdbcTemplate.update(sql);
            return "delete ok!";
        }
    
        /**
         * 修改用户
         */
        @ResponseBody
        @RequestMapping("/updateUser/{userId}")
        public String updateUser(@PathVariable("userId") int userId) {
            String sql = "update mybatis.user set name='赵六',pwd='123456' where id=" + userId + "";
            jdbcTemplate.update(sql);
            return "update Ok";
        }
    
        /**
         * 查询所有用户
         */
        @ResponseBody
        @RequestMapping("/userList")
    
        public List getUserAll() {
            String sql = "select * from user";
            List maps = jdbcTemplate.queryForList(sql);
            return maps;
        }
    }

    源码:

      数据库中所有能够配置的东西:DataSourceProperties

      1 /*
      2  * Copyright 2012-2020 the original author or authors.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      https://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.springframework.boot.autoconfigure.jdbc;
     18 
     19 import java.nio.charset.Charset;
     20 import java.util.LinkedHashMap;
     21 import java.util.List;
     22 import java.util.Map;
     23 import java.util.UUID;
     24 
     25 import javax.sql.DataSource;
     26 
     27 import org.springframework.beans.factory.BeanClassLoaderAware;
     28 import org.springframework.beans.factory.BeanCreationException;
     29 import org.springframework.beans.factory.InitializingBean;
     30 import org.springframework.boot.context.properties.ConfigurationProperties;
     31 import org.springframework.boot.jdbc.DataSourceBuilder;
     32 import org.springframework.boot.jdbc.DataSourceInitializationMode;
     33 import org.springframework.boot.jdbc.DatabaseDriver;
     34 import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
     35 import org.springframework.util.Assert;
     36 import org.springframework.util.ClassUtils;
     37 import org.springframework.util.StringUtils;
     38 
     39 /**
     40  * Base class for configuration of a data source.
     41  *
     42  * @author Dave Syer
     43  * @author Maciej Walkowiak
     44  * @author Stephane Nicoll
     45  * @author Benedikt Ritter
     46  * @author Eddú Meléndez
     47  * @author Scott Frederick
     48  * @since 1.1.0
     49  */
     50 @ConfigurationProperties(prefix = "spring.datasource")
     51 public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
     52 
     53     private ClassLoader classLoader;
     54 
     55     /**
     56      * Name of the datasource. Default to "testdb" when using an embedded database.
     57      */
     58     private String name;
     59 
     60     /**
     61      * Whether to generate a random datasource name.
     62      */
     63     private boolean generateUniqueName = true;
     64 
     65     /**
     66      * Fully qualified name of the connection pool implementation to use. By default, it
     67      * is auto-detected from the classpath.
     68      */
     69     private Class<? extends DataSource> type;
     70 
     71     /**
     72      * Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
     73      */
     74     private String driverClassName;
     75 
     76     /**
     77      * JDBC URL of the database.
     78      */
     79     private String url;
     80 
     81     /**
     82      * Login username of the database.
     83      */
     84     private String username;
     85 
     86     /**
     87      * Login password of the database.
     88      */
     89     private String password;
     90 
     91     /**
     92      * JNDI location of the datasource. Class, url, username and password are ignored when
     93      * set.
     94      */
     95     private String jndiName;
     96 
     97     /**
     98      * Mode to apply when determining if DataSource initialization should be performed
     99      * using the available DDL and DML scripts.
    100      */
    101     private DataSourceInitializationMode initializationMode = DataSourceInitializationMode.EMBEDDED;
    102 
    103     /**
    104      * Platform to use in the DDL or DML scripts (such as schema-${platform}.sql or
    105      * data-${platform}.sql).
    106      */
    107     private String platform = "all";
    108 
    109     /**
    110      * Schema (DDL) script resource references.
    111      */
    112     private List<String> schema;
    113 
    114     /**
    115      * Username of the database to execute DDL scripts (if different).
    116      */
    117     private String schemaUsername;
    118 
    119     /**
    120      * Password of the database to execute DDL scripts (if different).
    121      */
    122     private String schemaPassword;
    123 
    124     /**
    125      * Data (DML) script resource references.
    126      */
    127     private List<String> data;
    128 
    129     /**
    130      * Username of the database to execute DML scripts (if different).
    131      */
    132     private String dataUsername;
    133 
    134     /**
    135      * Password of the database to execute DML scripts (if different).
    136      */
    137     private String dataPassword;
    138 
    139     /**
    140      * Whether to stop if an error occurs while initializing the database.
    141      */
    142     private boolean continueOnError = false;
    143 
    144     /**
    145      * Statement separator in SQL initialization scripts.
    146      */
    147     private String separator = ";";
    148 
    149     /**
    150      * SQL scripts encoding.
    151      */
    152     private Charset sqlScriptEncoding;
    153 
    154     private EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection.NONE;
    155 
    156     private Xa xa = new Xa();
    157 
    158     private String uniqueName;
    159 
    160     @Override
    161     public void setBeanClassLoader(ClassLoader classLoader) {
    162         this.classLoader = classLoader;
    163     }
    164 
    165     @Override
    166     public void afterPropertiesSet() throws Exception {
    167         this.embeddedDatabaseConnection = EmbeddedDatabaseConnection.get(this.classLoader);
    168     }
    169 
    170     /**
    171      * Initialize a {@link DataSourceBuilder} with the state of this instance.
    172      * @return a {@link DataSourceBuilder} initialized with the customizations defined on
    173      * this instance
    174      */
    175     public DataSourceBuilder<?> initializeDataSourceBuilder() {
    176         return DataSourceBuilder.create(getClassLoader()).type(getType()).driverClassName(determineDriverClassName())
    177                 .url(determineUrl()).username(determineUsername()).password(determinePassword());
    178     }
    179 
    180     public String getName() {
    181         return this.name;
    182     }
    183 
    184     public void setName(String name) {
    185         this.name = name;
    186     }
    187 
    188     public boolean isGenerateUniqueName() {
    189         return this.generateUniqueName;
    190     }
    191 
    192     public void setGenerateUniqueName(boolean generateUniqueName) {
    193         this.generateUniqueName = generateUniqueName;
    194     }
    195 
    196     public Class<? extends DataSource> getType() {
    197         return this.type;
    198     }
    199 
    200     public void setType(Class<? extends DataSource> type) {
    201         this.type = type;
    202     }
    203 
    204     /**
    205      * Return the configured driver or {@code null} if none was configured.
    206      * @return the configured driver
    207      * @see #determineDriverClassName()
    208      */
    209     public String getDriverClassName() {
    210         return this.driverClassName;
    211     }
    212 
    213     public void setDriverClassName(String driverClassName) {
    214         this.driverClassName = driverClassName;
    215     }
    216 
    217     /**
    218      * Determine the driver to use based on this configuration and the environment.
    219      * @return the driver to use
    220      * @since 1.4.0
    221      */
    222     public String determineDriverClassName() {
    223         if (StringUtils.hasText(this.driverClassName)) {
    224             Assert.state(driverClassIsLoadable(), () -> "Cannot load driver class: " + this.driverClassName);
    225             return this.driverClassName;
    226         }
    227         String driverClassName = null;
    228         if (StringUtils.hasText(this.url)) {
    229             driverClassName = DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName();
    230         }
    231         if (!StringUtils.hasText(driverClassName)) {
    232             driverClassName = this.embeddedDatabaseConnection.getDriverClassName();
    233         }
    234         if (!StringUtils.hasText(driverClassName)) {
    235             throw new DataSourceBeanCreationException("Failed to determine a suitable driver class", this,
    236                     this.embeddedDatabaseConnection);
    237         }
    238         return driverClassName;
    239     }
    240 
    241     private boolean driverClassIsLoadable() {
    242         try {
    243             ClassUtils.forName(this.driverClassName, null);
    244             return true;
    245         }
    246         catch (UnsupportedClassVersionError ex) {
    247             // Driver library has been compiled with a later JDK, propagate error
    248             throw ex;
    249         }
    250         catch (Throwable ex) {
    251             return false;
    252         }
    253     }
    254 
    255     /**
    256      * Return the configured url or {@code null} if none was configured.
    257      * @return the configured url
    258      * @see #determineUrl()
    259      */
    260     public String getUrl() {
    261         return this.url;
    262     }
    263 
    264     public void setUrl(String url) {
    265         this.url = url;
    266     }
    267 
    268     /**
    269      * Determine the url to use based on this configuration and the environment.
    270      * @return the url to use
    271      * @since 1.4.0
    272      */
    273     public String determineUrl() {
    274         if (StringUtils.hasText(this.url)) {
    275             return this.url;
    276         }
    277         String databaseName = determineDatabaseName();
    278         String url = (databaseName != null) ? this.embeddedDatabaseConnection.getUrl(databaseName) : null;
    279         if (!StringUtils.hasText(url)) {
    280             throw new DataSourceBeanCreationException("Failed to determine suitable jdbc url", this,
    281                     this.embeddedDatabaseConnection);
    282         }
    283         return url;
    284     }
    285 
    286     /**
    287      * Determine the name to used based on this configuration.
    288      * @return the database name to use or {@code null}
    289      * @since 2.0.0
    290      */
    291     public String determineDatabaseName() {
    292         if (this.generateUniqueName) {
    293             if (this.uniqueName == null) {
    294                 this.uniqueName = UUID.randomUUID().toString();
    295             }
    296             return this.uniqueName;
    297         }
    298         if (StringUtils.hasLength(this.name)) {
    299             return this.name;
    300         }
    301         if (this.embeddedDatabaseConnection != EmbeddedDatabaseConnection.NONE) {
    302             return "testdb";
    303         }
    304         return null;
    305     }
    306 
    307     /**
    308      * Return the configured username or {@code null} if none was configured.
    309      * @return the configured username
    310      * @see #determineUsername()
    311      */
    312     public String getUsername() {
    313         return this.username;
    314     }
    315 
    316     public void setUsername(String username) {
    317         this.username = username;
    318     }
    319 
    320     /**
    321      * Determine the username to use based on this configuration and the environment.
    322      * @return the username to use
    323      * @since 1.4.0
    324      */
    325     public String determineUsername() {
    326         if (StringUtils.hasText(this.username)) {
    327             return this.username;
    328         }
    329         if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName(), determineUrl())) {
    330             return "sa";
    331         }
    332         return null;
    333     }
    334 
    335     /**
    336      * Return the configured password or {@code null} if none was configured.
    337      * @return the configured password
    338      * @see #determinePassword()
    339      */
    340     public String getPassword() {
    341         return this.password;
    342     }
    343 
    344     public void setPassword(String password) {
    345         this.password = password;
    346     }
    347 
    348     /**
    349      * Determine the password to use based on this configuration and the environment.
    350      * @return the password to use
    351      * @since 1.4.0
    352      */
    353     public String determinePassword() {
    354         if (StringUtils.hasText(this.password)) {
    355             return this.password;
    356         }
    357         if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName(), determineUrl())) {
    358             return "";
    359         }
    360         return null;
    361     }
    362 
    363     public String getJndiName() {
    364         return this.jndiName;
    365     }
    366 
    367     /**
    368      * Allows the DataSource to be managed by the container and obtained via JNDI. The
    369      * {@code URL}, {@code driverClassName}, {@code username} and {@code password} fields
    370      * will be ignored when using JNDI lookups.
    371      * @param jndiName the JNDI name
    372      */
    373     public void setJndiName(String jndiName) {
    374         this.jndiName = jndiName;
    375     }
    376 
    377     public DataSourceInitializationMode getInitializationMode() {
    378         return this.initializationMode;
    379     }
    380 
    381     public void setInitializationMode(DataSourceInitializationMode initializationMode) {
    382         this.initializationMode = initializationMode;
    383     }
    384 
    385     public String getPlatform() {
    386         return this.platform;
    387     }
    388 
    389     public void setPlatform(String platform) {
    390         this.platform = platform;
    391     }
    392 
    393     public List<String> getSchema() {
    394         return this.schema;
    395     }
    396 
    397     public void setSchema(List<String> schema) {
    398         this.schema = schema;
    399     }
    400 
    401     public String getSchemaUsername() {
    402         return this.schemaUsername;
    403     }
    404 
    405     public void setSchemaUsername(String schemaUsername) {
    406         this.schemaUsername = schemaUsername;
    407     }
    408 
    409     public String getSchemaPassword() {
    410         return this.schemaPassword;
    411     }
    412 
    413     public void setSchemaPassword(String schemaPassword) {
    414         this.schemaPassword = schemaPassword;
    415     }
    416 
    417     public List<String> getData() {
    418         return this.data;
    419     }
    420 
    421     public void setData(List<String> data) {
    422         this.data = data;
    423     }
    424 
    425     public String getDataUsername() {
    426         return this.dataUsername;
    427     }
    428 
    429     public void setDataUsername(String dataUsername) {
    430         this.dataUsername = dataUsername;
    431     }
    432 
    433     public String getDataPassword() {
    434         return this.dataPassword;
    435     }
    436 
    437     public void setDataPassword(String dataPassword) {
    438         this.dataPassword = dataPassword;
    439     }
    440 
    441     public boolean isContinueOnError() {
    442         return this.continueOnError;
    443     }
    444 
    445     public void setContinueOnError(boolean continueOnError) {
    446         this.continueOnError = continueOnError;
    447     }
    448 
    449     public String getSeparator() {
    450         return this.separator;
    451     }
    452 
    453     public void setSeparator(String separator) {
    454         this.separator = separator;
    455     }
    456 
    457     public Charset getSqlScriptEncoding() {
    458         return this.sqlScriptEncoding;
    459     }
    460 
    461     public void setSqlScriptEncoding(Charset sqlScriptEncoding) {
    462         this.sqlScriptEncoding = sqlScriptEncoding;
    463     }
    464 
    465     public ClassLoader getClassLoader() {
    466         return this.classLoader;
    467     }
    468 
    469     public Xa getXa() {
    470         return this.xa;
    471     }
    472 
    473     public void setXa(Xa xa) {
    474         this.xa = xa;
    475     }
    476 
    477     /**
    478      * XA Specific datasource settings.
    479      */
    480     public static class Xa {
    481 
    482         /**
    483          * XA datasource fully qualified name.
    484          */
    485         private String dataSourceClassName;
    486 
    487         /**
    488          * Properties to pass to the XA data source.
    489          */
    490         private Map<String, String> properties = new LinkedHashMap<>();
    491 
    492         public String getDataSourceClassName() {
    493             return this.dataSourceClassName;
    494         }
    495 
    496         public void setDataSourceClassName(String dataSourceClassName) {
    497             this.dataSourceClassName = dataSourceClassName;
    498         }
    499 
    500         public Map<String, String> getProperties() {
    501             return this.properties;
    502         }
    503 
    504         public void setProperties(Map<String, String> properties) {
    505             this.properties = properties;
    506         }
    507 
    508     }
    509 
    510     static class DataSourceBeanCreationException extends BeanCreationException {
    511 
    512         private final DataSourceProperties properties;
    513 
    514         private final EmbeddedDatabaseConnection connection;
    515 
    516         DataSourceBeanCreationException(String message, DataSourceProperties properties,
    517                 EmbeddedDatabaseConnection connection) {
    518             super(message);
    519             this.properties = properties;
    520             this.connection = connection;
    521         }
    522 
    523         DataSourceProperties getProperties() {
    524             return this.properties;
    525         }
    526 
    527         EmbeddedDatabaseConnection getConnection() {
    528             return this.connection;
    529         }
    530 
    531     }
    532 
    533 }
    View Code

      在SpringBoot中有:xxx.properties,肯定存在xxxAutoConfiguration自动配置的文件

    /*
     * Copyright 2012-2020 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.boot.autoconfigure.jdbc;
    
    import javax.sql.DataSource;
    import javax.sql.XADataSource;
    
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
    import org.springframework.boot.autoconfigure.condition.ConditionMessage;
    import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
    import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
    import org.springframework.util.StringUtils;
    
    /**
     * {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource}.
     *
     * @author Dave Syer
     * @author Phillip Webb
     * @author Stephane Nicoll
     * @author Kazuki Shimizu
     * @since 1.0.0
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
    @ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
    @EnableConfigurationProperties(DataSourceProperties.class)
    @Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
    public class DataSourceAutoConfiguration {
    
        @Configuration(proxyBeanMethods = false)
        @Conditional(EmbeddedDatabaseCondition.class)
        @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
        @Import(EmbeddedDataSourceConfiguration.class)
        protected static class EmbeddedDatabaseConfiguration {
    
        }
    
        @Configuration(proxyBeanMethods = false)
        @Conditional(PooledDataSourceCondition.class)
        @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
        @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
                DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
                DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
        protected static class PooledDataSourceConfiguration {
    
        }
    
        /**
         * {@link AnyNestedCondition} that checks that either {@code spring.datasource.type}
         * is set or {@link PooledDataSourceAvailableCondition} applies.
         */
        static class PooledDataSourceCondition extends AnyNestedCondition {
    
            PooledDataSourceCondition() {
                super(ConfigurationPhase.PARSE_CONFIGURATION);
            }
    
            @ConditionalOnProperty(prefix = "spring.datasource", name = "type")
            static class ExplicitType {
    
            }
    
            @Conditional(PooledDataSourceAvailableCondition.class)
            static class PooledDataSourceAvailable {
    
            }
    
        }
    
        /**
         * {@link Condition} to test if a supported connection pool is available.
         */
        static class PooledDataSourceAvailableCondition extends SpringBootCondition {
    
            @Override
            public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
                ConditionMessage.Builder message = ConditionMessage.forCondition("PooledDataSource");
                if (DataSourceBuilder.findType(context.getClassLoader()) != null) {
                    return ConditionOutcome.match(message.foundExactly("supported DataSource"));
                }
                return ConditionOutcome.noMatch(message.didNotFind("supported DataSource").atAll());
            }
    
        }
    
        /**
         * {@link Condition} to detect when an embedded {@link DataSource} type can be used.
         * If a pooled {@link DataSource} is available, it will always be preferred to an
         * {@code EmbeddedDatabase}.
         */
        static class EmbeddedDatabaseCondition extends SpringBootCondition {
    
            private static final String DATASOURCE_URL_PROPERTY = "spring.datasource.url";
    
            private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();
    
            @Override
            public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
                ConditionMessage.Builder message = ConditionMessage.forCondition("EmbeddedDataSource");
                if (hasDataSourceUrlProperty(context)) {
                    return ConditionOutcome.noMatch(message.because(DATASOURCE_URL_PROPERTY + " is set"));
                }
                if (anyMatches(context, metadata, this.pooledCondition)) {
                    return ConditionOutcome.noMatch(message.foundExactly("supported pooled data source"));
                }
                EmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(context.getClassLoader()).getType();
                if (type == null) {
                    return ConditionOutcome.noMatch(message.didNotFind("embedded database").atAll());
                }
                return ConditionOutcome.match(message.found("embedded database").items(type));
            }
    
            private boolean hasDataSourceUrlProperty(ConditionContext context) {
                Environment environment = context.getEnvironment();
                if (environment.containsProperty(DATASOURCE_URL_PROPERTY)) {
                    try {
                        return StringUtils.hasText(environment.getProperty(DATASOURCE_URL_PROPERTY));
                    }
                    catch (IllegalArgumentException ex) {
                        // Ignore unresolvable placeholder errors
                    }
                }
                return false;
            }
    
        }
    
    }
    View Code

    二、整合Druid


    1、Druid简介

      Java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,又不得不使用数据库连接池。

      Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。

      Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。

      Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

      Spring Boot 2.0 以上默认使用 Hikari 数据源,可以说 Hikari 与 Driud 都是当前 Java Web 上最优秀的数据源,我们来重点介绍 Spring Boot 如何集成 Druid 数据源,如何实现数据库监控。

       Github地址:https://github.com/alibaba/druid/

    基本配置

    配置缺省值说明
    name   配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:“DataSource-” + System.identityHashCode(this)
    jdbcUrl   连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
    username   连接数据库的用户名
    password   连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
    driverClassName 根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)
    initialSize 0 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
    maxActive 8 最大连接池数量
    maxIdle 8 已经不再使用,配置了也没效果
    minIdle   最小连接池数量
    maxWait   获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
    poolPreparedStatements false 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
    maxOpenPreparedStatements -1 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
    validationQuery   用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
    testOnBorrow true 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
    testOnReturn false 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
    testWhileIdle false 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
    timeBetweenEvictionRunsMillis   有两个含义: 1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
    numTestsPerEvictionRun   不再使用,一个DruidDataSource只支持一个EvictionRun
    minEvictableIdleTimeMillis    
    connectionInitSqls   物理连接初始化的时候执行的sql
    exceptionSorter 根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接
    filters   属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
    proxyFilters   类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系

     2、Druid的使用

    • 添加druid数据源 pom.xml
    <!--阿里druid数据源-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.21</version>
    </dependency>
    <!--druid数据源依赖-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.17</version>
    </dependency>
    <!--log4j日志监控-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    • 切换数据源 application.yaml
    spring:
      datasource:
        username: root
        password: zhixi158
        url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
        driver-class-name: com.mysql.cj.jdbc.Driver
    
        # 更改数据源
        type: com.alibaba.druid.pool.DruidDataSource
    
        #druid 数据源专有配置
        druid:
          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
          
          #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
          #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
          #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
          filters: stat,wall,log4j
          maxPoolPreparedStatementPerConnectionSize: 20
          useGlobalDataSourceStat: true
          connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
    
    • 测试druid的日志监控 config/DruidConfigUraction.java
    package com.zhixi.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 DruidConfiguration {
    
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource druidDataSource(){
            return new DruidDataSource();
        }
    
        @Bean
        //后台监控功能
        //因为SpringBoot内置了Servlet容器,所以没有Web.xml,替代方法:ServletRegistrationBean
        public ServletRegistrationBean statViewServlet(){
    
            ServletRegistrationBean bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
            //后台需要有人登陆,账号密码配置
            HashMap<String,String> map = new HashMap<>();
            //增加配置
            map.put("loginUsername","admin");//登陆的key,是固定的,不能自己定义成其他的
            map.put("loginPassword","123456");
    
            //允许谁可以访问
            map.put("allow","localhost");
    
            bean.setInitParameters(map);//初始化参数
            return bean;
        }
    
        //配置 Druid 监控 之  web 监控的 filter
        //WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
        @Bean
        public FilterRegistrationBean webStatFilter() {
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.setFilter(new WebStatFilter());
    
            //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
            Map<String, String> initParams = new HashMap<>();
            initParams.put("exclusions", "*.js,*.css,/druid/*");
            bean.setInitParameters(initParams);
    
            //"/*" 表示过滤所有请求
            bean.setUrlPatterns(Arrays.asList("/*"));
            return bean;
        }
    }

    访问:localhost:8080/druid,输入账号密码即可访问监控主页!

     三、整合mybatis


     1、整合包

      为了方便我这里就放了学习SpringBoot到现在所用的依赖,有注释方便查看

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </dependency>
            <!--阿里druid数据源-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.21</version>
            </dependency>
            <!--druid数据源依赖-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.17</version>
            </dependency>
            <!--log4j日志监控-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
            <!--
                spring默认使用yml中的配置,解决
                @ConfigurationProperties(prefix = "person")爆红
            -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
    
            <!--JSR303数据校验-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-validation</artifactId>
            </dependency>
    
            <!--thymeleaf模板引擎-->
            <dependency>
                <groupId>org.thymeleaf</groupId>
                <artifactId>thymeleaf-spring5</artifactId>
            </dependency>
            <dependency>
                <groupId>org.thymeleaf.extras</groupId>
                <artifactId>thymeleaf-extras-java8time</artifactId>
            </dependency>
            <!--整合mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.1</version>
            </dependency>
        </dependencies>

    2、实体类:popo/User.java

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
        private Integer id;
        private String name;
        private String pwd;
    }

    3、业务接口:mapper/UserMapper.java

    @Component
    @Mapper
    public interface UserMapper {
        /**
         * 添加用户
         */
        int addUser(User user);
    
        /**
         * 修改用户
         */
        int updateUser(User user);
    
        /**
         * 删除用户
         */
        int delUser(int id);
    
        /**
         * 根据id查询用户
         */
        User queryUserById(@Param("userId") int id);
    
        /**
         * 查询全部用户
         */
        List<User> queryUserAll();
    
    }
    

    4、mybatis映射(CRUD):/resources/mybatis/mapper/UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.zhixi.mapper.UserMapper">
        <select id="queryUserAll" resultType="user">
            select *
            from mybatis.user;
        </select>
    
        <select id="queryUserById" resultType="user" parameterType="int">
            select *
            from mybatis.user
            where id = #{userId}
        </select>
    
        <delete id="delUser" parameterType="int">
            delete
            from mybatis.user
            where id = #{id}
        </delete>
    
        <update id="updateUser" parameterType="user">
            update mybatis.user
            set name=#{name},
                pwd=#{pwd}
            where id = #{id}
        </update>
    
        <insert id="addUser" parameterType="user">
            insert into mybatis.user(id, name, pwd)
            values (#{id}, #{name}, #{pwd});
        </insert>
    </mapper>
    

    5、配置文件:application.properties

    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    spring.datasource.username=root
    spring.datasource.password=zhixi158
    
    
    # 整合mybatis
    #-----------------------------
    # 给实体类起别名
    mybatis.type-aliases-package=com.zhixi.pojo
    # mapper映射
    mybatis.mapper-locations=classpath:mybatis/mapper/UserMapper.xml
    

    6、业务接口的实现:controller/UserController

    @Controller
    public class UserController {
    
        @Autowired
        private UserMapper userMapper;
    
        /**
         * @return 查询全部用户
         */
        @ResponseBody
        @RequestMapping("/queryUser")
        public List<User> queryUserAll() {
            List<User> list = userMapper.queryUserAll();
            for (User user : list) {
                System.out.println(user);
            }
            return list;
        }
    
        /**
         * @param id
         * @return 根据id查询用户
         */
        @ResponseBody
        @RequestMapping("/queryUserById/{id}")
        public User queryUserById(@PathVariable("id") int id) {
            User user = userMapper.queryUserById(id);
            System.out.println(user);
            return user;
        }
    
        /**
         * @param id
         * @return 根据id删除用户
         */
        @ResponseBody
        @RequestMapping("/delUser/{id}")
        public String delUser(@PathVariable("id") int id) {
            int i = userMapper.delUser(id);
            return i >= 1 ? "删除成功" : "删除失败";
        }
    
        /**
         * @return 根据id修改用户
         */
        @ResponseBody
        @RequestMapping("/updateUser/{id}/{userName}/{userPwd}")
        public String updateUser(@PathVariable("id") int id,
                                 @PathVariable("userName") String userName,
                                 @PathVariable("userPwd") String userPwd) {
            int i = userMapper.updateUser(new User(id, userName, userPwd));
            return i >= 1 ? "修改成功" : "修改失败";
        }
    
        /**
         * @return 添加用户
         */
        @ResponseBody
        @RequestMapping("/addUser/{id}/{userName}/{userPwd}")
        public String addUser(@PathVariable("id") int id,
                              @PathVariable("userName") String userName,
                              @PathVariable("userPwd") String userPwd) {
            int i = userMapper.addUser(new User(id, userName, userPwd));
            return i >= 1 ? "添加用户成功" : "添加用户失败";
        }
    }
    

     地址访问:localhost:8080/url地址即可实现对应操作

      

     
  • 相关阅读:
    Minimum Inversion Number(归并排序)
    Ultra-QuickSort(归并排序)
    求逆序数(归并排序)
    Hat's Fibonacci(大数,好)
    Baskets of Gold Coins
    Permutation Recovery(模拟)
    反恐训练营(LCS)
    I Hate It(线段树)
    敌兵布阵
    Django报错:提交表单报错---RuntimeError: You called this URL via POST, but the URL doesn’t end in a slash and you have APPEND_SLASH set.
  • 原文地址:https://www.cnblogs.com/zhangzhixi/p/14335345.html
Copyright © 2011-2022 走看看