第16章 Spring Boot + Kotlin: 下一代 Java 服务端开发

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: 第16章 Spring Boot + Kotlin: 下一代 Java 服务端开发16.1 Kotlin 简介16.2 Kotlin 与 Java 的无缝集成16.

第16章 Spring Boot + Kotlin: 下一代 Java 服务端开发

16.1 Kotlin 简介

16.2 Kotlin 与 Java 的无缝集成

16.3 Spring Boot 集成 Kotlin 开发实例详解

image.png
image.png
image.png
image.png

Nextj2eeApplication.kt

package com.kotlin.springboot.nextj2ee

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class Nextj2eeApplication

fun main(args: Array<String>) {
    runApplication<Nextj2eeApplication>(*args)
}

build.gradle

buildscript {
    ext {
        kotlinVersion = '1.1.60'
        springBootVersion = '2.0.0.M6'
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
    }
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.kotlin.springboot'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-freemarker')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile("org.jetbrains.kotlin:kotlin-stdlib-jre8")
    compile("org.jetbrains.kotlin:kotlin-reflect")
    runtime('mysql:mysql-connector-java')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
2017-11-22 10:42:57.949  INFO 13877 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2017-11-22 10:42:58.000  INFO 13877 --- [           main] utoConfigurationReportLoggingInitializer : 

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-11-22 10:42:58.004 ERROR 13877 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Cannot determine embedded database driver class for database type NONE

Action:

If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).


Process finished with exit code 1

BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).

Database dataSource Config

2017-11-22 11:26:24.961  INFO 14423 --- [           main] com.zaxxer.hikari.HikariDataSource       : testdb - Starting...
2017-11-22 11:26:25.306  INFO 14423 --- [           main] com.zaxxer.hikari.HikariDataSource       : testdb - Start completed.
2017-11-22 11:26:25.373  INFO 14423 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2017-11-22 11:26:25.385  INFO 14423 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
2017-11-22 11:26:25.481  INFO 14423 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.2.12.Final}
2017-11-22 11:26:25.485  INFO 14423 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2017-11-22 11:26:25.544  INFO 14423 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-11-22 11:26:25.738  INFO 14423 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2017-11-22 11:26:26.020  INFO 14423 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'

hibernate.properties

#
# Hibernate, Relational Persistence for Idiomatic Java
# org.hibernate.cfg.AvailableSettings
#
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
#
######################
### Query Language ###
######################
## define query language constants / function names
#hibernate.query.substitutions yes 'Y', no 'N'
## select the classic query parser
#hibernate.query.factory_class org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory
#################
### Platforms ###
#################
## JNDI Datasource
#hibernate.connection.datasource jdbc/test
#hibernate.connection.username db2
#hibernate.connection.password db2
## HypersonicSQL
#hibernate.dialect org.hibernate.dialect.HSQLDialect
#hibernate.connection.driver_class org.hsqldb.jdbcDriver
#hibernate.connection.username sa
#hibernate.connection.password
#hibernate.connection.url jdbc:hsqldb:./build/db/hsqldb/hibernate
#hibernate.connection.url jdbc:hsqldb:hsql://localhost
#hibernate.connection.url jdbc:hsqldb:test
## H2 (www.h2database.com)
#hibernate.dialect org.hibernate.dialect.H2Dialect
#hibernate.connection.driver_class org.h2.Driver
#hibernate.connection.username sa
#hibernate.connection.password
#hibernate.connection.url jdbc:h2:mem:./build/db/h2/hibernate
#hibernate.connection.url jdbc:h2:testdb/h2test
#hibernate.connection.url jdbc:h2:mem:imdb1
#hibernate.connection.url jdbc:h2:tcp://dbserv:8084/sample;
#hibernate.connection.url jdbc:h2:ssl://secureserv:8085/sample;
#hibernate.connection.url jdbc:h2:ssl://secureserv/testdb;cipher=AES
## MySQL
hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username gavin
#hibernate.connection.password
## Oracle
#hibernate.dialect org.hibernate.dialect.Oracle8iDialect
#hibernate.dialect org.hibernate.dialect.Oracle9iDialect
#hibernate.dialect org.hibernate.dialect.Oracle10gDialect
#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver
#hibernate.connection.username ora
#hibernate.connection.password ora
#hibernate.connection.url jdbc:oracle:thin:@localhost:1521:orcl
#hibernate.connection.url jdbc:oracle:thin:@localhost:1522:XE
## PostgreSQL
#hibernate.dialect org.hibernate.dialect.PostgreSQLDialect
#hibernate.connection.driver_class org.postgresql.Driver
#hibernate.connection.url jdbc:postgresql:template1
#hibernate.connection.username pg
#hibernate.connection.password
## DB2
#hibernate.dialect org.hibernate.dialect.DB2Dialect
#hibernate.connection.driver_class com.ibm.db2.jcc.DB2Driver
#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver
#hibernate.connection.url jdbc:db2://localhost:50000/somename
#hibernate.connection.url jdbc:db2:somename
#hibernate.connection.username db2
#hibernate.connection.password db2
## TimesTen
#hibernate.dialect org.hibernate.dialect.TimesTenDialect
#hibernate.connection.driver_class com.timesten.jdbc.TimesTenDriver
#hibernate.connection.url jdbc:timesten:direct:test
#hibernate.connection.username
#hibernate.connection.password
## DB2/400
#hibernate.dialect org.hibernate.dialect.DB2400Dialect
#hibernate.connection.username user
#hibernate.connection.password password
## Native driver
#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver
#hibernate.connection.url jdbc:db2://systemname
## Toolbox driver
#hibernate.connection.driver_class com.ibm.as400.access.AS400JDBCDriver
#hibernate.connection.url jdbc:as400://systemname
## Derby (not supported!)
#hibernate.dialect org.hibernate.dialect.DerbyDialect
#hibernate.connection.driver_class org.apache.derby.jdbc.EmbeddedDriver
#hibernate.connection.username
#hibernate.connection.password
#hibernate.connection.url jdbc:derby:build/db/derby/hibernate;create=true
## Sybase
#hibernate.dialect org.hibernate.dialect.SybaseDialect
#hibernate.connection.driver_class com.sybase.jdbc2.jdbc.SybDriver
#hibernate.connection.username sa
#hibernate.connection.password sasasa
#hibernate.connection.url jdbc:sybase:Tds:co3061835-a:5000/tempdb
## Mckoi SQL
#hibernate.dialect org.hibernate.dialect.MckoiDialect
#hibernate.connection.driver_class com.mckoi.JDBCDriver
#hibernate.connection.url jdbc:mckoi:///
#hibernate.connection.url jdbc:mckoi:local://C:/mckoi1.0.3/db.conf
#hibernate.connection.username admin
#hibernate.connection.password nimda
## SAP DB
#hibernate.dialect org.hibernate.dialect.SAPDBDialect
#hibernate.connection.driver_class com.sap.dbtech.jdbc.DriverSapDB
#hibernate.connection.url jdbc:sapdb://localhost/TST
#hibernate.connection.username TEST
#hibernate.connection.password TEST
#hibernate.query.substitutions yes 'Y', no 'N'
## MS SQL Server
#hibernate.dialect org.hibernate.dialect.SQLServerDialect
#hibernate.connection.username sa
#hibernate.connection.password sa
## JSQL Driver
#hibernate.connection.driver_class com.jnetdirect.jsql.JSQLDriver
#hibernate.connection.url jdbc:JSQLConnect://1E1/test
## JTURBO Driver
#hibernate.connection.driver_class com.newatlanta.jturbo.driver.Driver
#hibernate.connection.url jdbc:JTurbo://1E1:1433/test
## WebLogic Driver
#hibernate.connection.driver_class weblogic.jdbc.mssqlserver4.Driver
#hibernate.connection.url jdbc:weblogic:mssqlserver4:1E1:1433
## Microsoft Driver (not recommended!)
#hibernate.connection.driver_class com.microsoft.jdbc.sqlserver.SQLServerDriver
#hibernate.connection.url jdbc:microsoft:sqlserver://1E1;DatabaseName=test;SelectMethod=cursor
## The New Microsoft Driver
#hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver
#hibernate.connection.url jdbc:sqlserver://localhost
## jTDS (since version 0.9)
#hibernate.connection.driver_class net.sourceforge.jtds.jdbc.Driver
#hibernate.connection.url jdbc:jtds:sqlserver://1E1/test
## Interbase
#hibernate.dialect org.hibernate.dialect.InterbaseDialect
#hibernate.connection.username sysdba
#hibernate.connection.password masterkey
## DO NOT specify hibernate.connection.sqlDialect
## InterClient
#hibernate.connection.driver_class interbase.interclient.Driver
#hibernate.connection.url jdbc:interbase://localhost:3060/C:/firebird/test.gdb
## Pure Java
#hibernate.connection.driver_class org.firebirdsql.jdbc.FBDriver
#hibernate.connection.url jdbc:firebirdsql:localhost/3050:/firebird/test.gdb
## Pointbase
#hibernate.dialect org.hibernate.dialect.PointbaseDialect
#hibernate.connection.driver_class com.pointbase.jdbc.jdbcUniversalDriver
#hibernate.connection.url jdbc:pointbase:embedded:sample
#hibernate.connection.username PBPUBLIC
#hibernate.connection.password PBPUBLIC
## Ingres
## older versions (before Ingress 2006)
#hibernate.dialect org.hibernate.dialect.IngresDialect
#hibernate.connection.driver_class ca.edbc.jdbc.EdbcDriver
#hibernate.connection.url jdbc:edbc://localhost:II7/database
#hibernate.connection.username user
#hibernate.connection.password password
## Ingres 2006 or later
#hibernate.dialect org.hibernate.dialect.IngresDialect
#hibernate.connection.driver_class com.ingres.jdbc.IngresDriver
#hibernate.connection.url jdbc:ingres://localhost:II7/database;CURSOR=READONLY;auto=multi
#hibernate.connection.username user
#hibernate.connection.password password
## Mimer SQL
#hibernate.dialect org.hibernate.dialect.MimerSQLDialect
#hibernate.connection.driver_class com.mimer.jdbc.Driver
#hibernate.connection.url jdbc:mimer:multi1
#hibernate.connection.username hibernate
#hibernate.connection.password hibernate
## InterSystems Cache
#hibernate.dialect org.hibernate.dialect.Cache71Dialect
#hibernate.connection.driver_class com.intersys.jdbc.CacheDriver
#hibernate.connection.username _SYSTEM
#hibernate.connection.password SYS
#hibernate.connection.url jdbc:Cache://127.0.0.1:1972/HIBERNATE
#################################
### Hibernate Connection Pool ###
#################################
hibernate.connection.pool_size 1
###########################
### C3P0 Connection Pool###
###########################
#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements 100
#hibernate.c3p0.idle_test_period 3000
#hibernate.c3p0.acquire_increment 2
#hibernate.c3p0.validate false
##############################
### Proxool Connection Pool###
##############################
## Properties for external configuration of Proxool
#hibernate.proxool.pool_alias pool1
## Only need one of the following
#hibernate.proxool.existing_pool true
#hibernate.proxool.xml proxool.xml
#hibernate.proxool.properties proxool.properties
#################################
### Plugin ConnectionProvider ###
#################################
## use a custom ConnectionProvider (if not set, Hibernate will choose a built-in ConnectionProvider using hueristics)
#hibernate.connection.provider_class org.hibernate.connection.DriverManagerConnectionProvider
#hibernate.connection.provider_class org.hibernate.connection.DatasourceConnectionProvider
#hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider
#hibernate.connection.provider_class org.hibernate.connection.ProxoolConnectionProvider
#######################
### Transaction API ###
#######################
## Enable automatic flush during the JTA beforeCompletion() callback
## (This setting is relevant with or without the Transaction API)
#hibernate.transaction.flush_before_completion
## Enable automatic session close at the end of transaction
## (This setting is relevant with or without the Transaction API)
#hibernate.transaction.auto_close_session
## the Transaction API abstracts application code from the underlying JTA or JDBC transactions
#hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory
## to use JTATransactionFactory, Hibernate must be able to locate the UserTransaction in JNDI
## default is java:comp/UserTransaction
## you do NOT need this setting if you specify hibernate.transaction.manager_lookup_class
#jta.UserTransaction jta/usertransaction
#jta.UserTransaction javax.transaction.UserTransaction
#jta.UserTransaction UserTransaction
## to use the second-level cache with JTA, Hibernate must be able to obtain the JTA TransactionManager
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.JBossTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WeblogicTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WebSphereTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.OrionTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.ResinTransactionManagerLookup
##############################
### Miscellaneous Settings ###
##############################
## print all generated SQL to the console
#hibernate.show_sql true
## format SQL in log and console
hibernate.format_sql true
## add comments to the generated SQL
#hibernate.use_sql_comments true
## generate statistics
#hibernate.generate_statistics true
## auto schema export
#hibernate.hbm2ddl.auto create-drop
#hibernate.hbm2ddl.auto create
#hibernate.hbm2ddl.auto update
#hibernate.hbm2ddl.auto validate
## specify a default schema and catalog for unqualified tablenames
#hibernate.default_schema test
#hibernate.default_catalog test
## enable ordering of SQL UPDATEs by primary key
#hibernate.order_updates true
## set the maximum depth of the outer join fetch tree
hibernate.max_fetch_depth 1
## set the default batch size for batch fetching
#hibernate.default_batch_fetch_size 8
## rollback generated identifier values of deleted entities to default values
#hibernate.use_identifier_rollback true
## enable bytecode reflection optimizer (disabled by default)
#hibernate.bytecode.use_reflection_optimizer true
#####################
### JDBC Settings ###
#####################
## specify a JDBC isolation level
#hibernate.connection.isolation 4
## enable JDBC autocommit (not recommended!)
#hibernate.connection.autocommit true
## set the JDBC fetch size
#hibernate.jdbc.fetch_size 25
## set the maximum JDBC 2 batch size (a nonzero value enables batching)
#hibernate.jdbc.batch_size 5
#hibernate.jdbc.batch_size 0
## enable batch updates even for versioned data
#hibernate.jdbc.batch_versioned_data true
## enable use of JDBC 2 scrollable ResultSets (specifying a Dialect will cause Hibernate to use a sensible default)
#hibernate.jdbc.use_scrollable_resultset true
## use streams when writing binary types to / from JDBC
#hibernate.jdbc.use_streams_for_binary true
## use JDBC 3 PreparedStatement.getGeneratedKeys() to get the identifier of an inserted row
#hibernate.jdbc.use_get_generated_keys false
## choose a custom JDBC batcher
# hibernate.jdbc.factory_class
## enable JDBC result set column alias caching
## (minor performance enhancement for broken JDBC drivers)
# hibernate.jdbc.wrap_result_sets
## choose a custom SQL exception converter
#hibernate.jdbc.sql_exception_converter
##########################
### Second-level Cache ###
##########################
## optimize cache for minimal "puts" instead of minimal "gets" (good for clustered cache)
#hibernate.cache.use_minimal_puts true
## set a prefix for cache region names
#hibernate.cache.region_prefix hibernate.test
## disable the second-level cache
#hibernate.cache.use_second_level_cache false
## enable the query cache
#hibernate.cache.use_query_cache true
## store the second-level cache entries in a more human-friendly format
#hibernate.cache.use_structured_entries true
## choose a cache implementation
#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.InfinispanRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.JndiInfinispanRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.internal.EhCacheRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.internal.SingletonEhCacheRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.internal.NoCachingRegionFactory
## choose a custom query cache implementation
#hibernate.cache.query_cache_factory
############
### JNDI ###
############
## specify a JNDI name for the SessionFactory
#hibernate.session_factory_name hibernate/session_factory
## Hibernate uses JNDI to bind a name to a SessionFactory and to look up the JTA UserTransaction;
## if hibernate.jndi.* are not specified, Hibernate will use the default InitialContext() which
## is the best approach in an application server
#file system
#hibernate.jndi.class com.sun.jndi.fscontext.RefFSContextFactory
#hibernate.jndi.url file:/
#WebSphere
#hibernate.jndi.class com.ibm.websphere.naming.WsnInitialContextFactory
#hibernate.jndi.url iiop://localhost:900/

2017-11-22 11:55:17.205 INFO 14721 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.2.12.Final}
2017-11-22 11:55:17.208 INFO 14721 --- [ main] org.hibernate.cfg.Environment : HHH000205: Loaded properties from resource hibernate.properties: {hibernate.connection.driver_class=com.mysql.jdbc.Driver, hibernate.format_sql=true, hibernate.dialect=org.hibernate.dialect.MySQLDialect, hibernate.bytecode.use_reflection_optimizer=false, hibernate.max_fetch_depth=1, hibernate.connection.pool_size=1}
2017-11-22 11:55:17.261 INFO 14721 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-11-22 11:55:17.449 INFO 14721 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2017-11-22 11:55:17.665 INFO 14721 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'

Article.kt

package com.kotlin.springboot.nextj2ee.entity

import java.util.*
import javax.persistence.*

@Entity
class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = -1

    lateinit var author: String
    lateinit var title: String
    @Column(name = "url", unique = true, length = 512)
    lateinit var url: String
    @Lob
    lateinit var content: String
    lateinit var gmtCreate: Date
    lateinit var gmtModify: Date

}

对应的Hibernate 启动日志

Hibernate: 
    
    drop table if exists article
Hibernate: 
    
    create table article (
       id bigint not null auto_increment,
        author varchar(255),
        content longtext,
        gmt_create datetime,
        gmt_modify datetime,
        title varchar(255),
        url varchar(250),
        primary key (id)
    ) engine=MyISAM
Hibernate: 
    
    alter table article 
       add constraint UK_la4e9l2g2otn85r9ih4btnmi unique (url)

url varchar(250)

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Specified key was too long; max key length is 1000 bytes
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488) ~[na:na]
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.Util.getInstance(Util.java:408) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:943) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3973) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3909) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2527) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2680) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2483) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2441) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.StatementImpl.executeInternal(StatementImpl.java:845) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:745) ~[mysql-connector-java-5.1.44.jar:5.1.44]
    at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:95) ~[HikariCP-2.7.2.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) ~[HikariCP-2.7.2.jar:na]
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
    ... 33 common frames omitted

由 Entity 类生成的表结构:

image.png

唯一索引信息:

image.png

MySQL 的 utf8mb4 (most bytes 4)编码

一、简介

MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。

二、内容描述

那上面说了既然utf8能够存下大部分中文汉字,那为什么还要使用utf8mb4呢? 原来mysql支持的 utf8 编码最大字符长度为 3 字节,如果遇到 4 字节的宽字符就会插入异常了。三个字节的 UTF-8 最大能编码的 Unicode 字符是 0xffff,也就是 Unicode 中的基本多文种平面(BMP)。也就是说,任何不在基本多文本平面的 Unicode字符,都无法使用 Mysql 的 utf8 字符集存储。包括 Emoji 表情(Emoji 是一种特殊的 Unicode 编码,常见于 ios 和 android 手机上),和很多不常用的汉字,以及任何新增的 Unicode 字符等等。
三、问题根源
最初的 UTF-8 格式使用一至六个字节,最大能编码 31 位字符。最新的 UTF-8 规范只使用一到四个字节,最大能编码21位,正好能够表示所有的 17个 Unicode 平面。
utf8 是 Mysql 中的一种字符集,只支持最长三个字节的 UTF-8字符,也就是 Unicode 中的基本多文本平面。
Mysql 中的 utf8 为什么只支持持最长三个字节的 UTF-8字符呢?我想了一下,可能是因为 Mysql 刚开始开发那会,Unicode 还没有辅助平面这一说呢。那时候,Unicode 委员会还做着 “65535 个字符足够全世界用了”的美梦。Mysql 中的字符串长度算的是字符数而非字节数,对于 CHAR 数据类型来说,需要为字符串保留足够的长。当使用 utf8 字符集时,需要保留的长度就是 utf8 最长字符长度乘以字符串长度,所以这里理所当然的限制了 utf8 最大长度为 3,比如 CHAR(100) Mysql 会保留 300字节长度。至于后续的版本为什么不对 4 字节长度的 UTF-8 字符提供支持,我想一个是为了向后兼容性的考虑,还有就是基本多文种平面之外的字符确实很少用到。
要在 Mysql 中保存 4 字节长度的 UTF-8 字符,需要使用 utf8mb4 字符集,但只有 5.5.3 版本以后的才支持(查看版本: select version();)。我觉得,为了获取更好的兼容性,应该总是使用 utf8mb4 而非 utf8. 对于 CHAR 类型数据,utf8mb4 会多消耗一些空间,根据 Mysql 官方建议,使用 VARCHAR 替代 CHAR。

16.4 本章小结

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1天前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
12天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
69 13
|
17天前
|
算法 Java API
如何使用Java开发获得淘宝商品描述API接口?
本文详细介绍如何使用Java开发调用淘宝商品描述API接口,涵盖从注册淘宝开放平台账号、阅读平台规则、创建应用并申请接口权限,到安装开发工具、配置开发环境、获取访问令牌,以及具体的Java代码实现和注意事项。通过遵循这些步骤,开发者可以高效地获取商品详情、描述及图片等信息,为项目和业务增添价值。
51 10
|
10天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
48 2
|
2天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
2天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
3天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
14 3
|
3天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
30 2
|
11天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
42 6
|
26天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####