26.3.3. JDBC引用

26.3.3.1. Driver/Datasource类名,URL语法,以及Connector/J的配置属性

在MySQL Connector/J中实现了java.sql.Driver的类名是“com.mysql.jdbc.Driver”。“org.gjt.mm.mysql.Driver”类名任是可用的,以保持与MM.MySQL的向后兼容性。注册驱动程序,或配置软件以使用MySQL Connector/J时,应使用该类名。

用于MySQL Connector/J的JDBC URL格式如下,方括号“[, ]”的项为可选项:

jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...

如果未指定主机名,默认为“127.0.0.1”。如果未指定端口,默认为“3306”,它是MySQL服务器的默认端口号。

jdbc:mysql://[host:port],[host:port].../[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...

如果未指定数据库,将使用无“当前”数据库进行连接。在这种情况下,需要在连接实例上调用“setCatalog()”方法,或在SQL中使用数据库名指定完整的表名(即“SELECT dbname.tablename.colname FROM dbname.tablename...”)。不指定连接时使用的数据库,该选项通常仅在创建用于处理多个数据库的工具时才有用,例如GUI数据库管理器。

MySQL Connector/J支持故障切换功能。这样,就允许驱动程序切换至“从”主机上,并仍能执行只读查询。仅当连接处于autoCommit(true)状态时,才会出现故障切换,这是因为当事务正在进行时,无法可靠地保证故障切换。在事务/连接结束后,大多数应用服务器和连接池均会将autoCommit设置为“真”。

故障切换功能具有下述行为方式:

如果URL属性“autoReconnect”为“假”:故障切换仅会在连接初始化过程中出现,当驱动程序判断第1台主机再次可用时,将返回。

如果URL属性“autoReconnect”为“真”:当驱动程序判断连接失败时(在任意查询之前),将出现故障切换,而且当驱动程序判断第1台主机再次可用时(发出queriesBeforeRetryMaster查询之后),将返回第1台主机。

在任何一种情况下,当你连接到经过故障切换的服务器时,会将连接设置为只读状态,因此,对于会更改数据的查询来说,将抛出异常(MySQL服务器不会处理该查询)。

配置属性定义了Connector/J与MySQL服务器进行连接的方式。除非作了其他说明,否则可以为DataSource对象或Connection对象设置属性。

可采用下述方式的一种设置Configuration(配置)属性:

·         在java.sql.DataSource的MySQL实施实例上使用set*()方法(它是使用java.sql.DataSource实施实例时的首选方法):

o        com.mysql.jdbc.jdbc2.optional.MysqlDataSource

o        com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource

·         作为传递给DriverManager.getConnection()或Driver.connect()的java.util.Properties实例中的 键/值对。

·         作为URL中的JDBC URL参数,以传递给java.sql.DriverManager.getConnection()、java.sql.Driver.connect()、或javax.sql.DataSource的setURL()方法的MySQL实施实例。

注释:

如果你用来配置JDBC URL的方法是基于XML的,需要使用XML字符“&”来隔开配置参数,“&”是XML的保留字符。

在下面的表各中,列出了这些属性:

表26.1. 连接属性 

属性名

定义

要求?

默认值

版本

Connection/Authentication(连接/鉴定)

user

连接的用户

No

 

全部

password

连接时使用的密码。

No

 

全部

socketFactory

驱动程序用于创建与服务器套接字连接的类的名称。该类必须实现了接口“com.mysql.jdbc.SocketFactory”,并有公共无参量构造函数。

No

com.mysql.jdbc.StandardSocketFactory

3.0.3

connectTimeout

套接字连接的超时(单位为毫秒),0表示无超时。仅对JDK-1.4或更新版本有效。默认值为“0”。

No

0

3.0.1

socketTimeout

网络套接字连接的超时(默认值0表示无超时)。

No

0

3.0.1

useConfigs

在解析URL属性或应用用户指定的属性之前,加载由逗号“,”分隔的配置属性列表。在文档的“配置”部分中解释了这些配置。

No

 

3.1.5

interactiveClient

设置CLIENT_INTERACTIVE标志,根据INTERACTIVE_TIMEOUT而不是WAIT_TIMEOUT向MySQL通报超时连接。

No

false

3.1.0

propertiesTransform

com.mysql.jdbc.ConnectionPropertiesTransform的1个实施实例,在尝试连接之前,驱动程序将使用它来更改传递给驱动的URL属性。

No

 

3.1.4

useCompression

与服务器进行通信时采用zlib压缩(真/假)? 默认值为“假”。

No

false

3.0.17

High Availability and Clustering(高可用性和簇集)

autoReconnect

驱动程序是否应尝试再次建立失效的和/或死连接? 如果允许,对于在失效或死连接上发出的查询(属于当前事务),驱动程序将抛出异常,但在新事务的连接上发出下一个查询时,将尝试再连接。不推荐使用该特性,这是因为,当应用程序不能恰当处理SQLExceptions时,它会造成与会话状态和数据一致性有关的副作用,设计它的目的仅用于下述情况,即,当你无法配置应用程序来恰当处理因死连接和/或无效连接导致的SQLExceptions时。作为可选方式,可将MySQL服务器变量“wait_timeout”设置为较高的值,而不是默认的8小时。

No

false

1.1

autoReconnectForPools

使用适合于连接池的再连接策略(默认值为“假”)。

No

false

3.1.3

failOverReadOnly

在autoReconnect模式下出现故障切换时,是否应将连接设置为“只读”?

No

true

3.0.12

reconnectAtTxEnd

如果将autoReconnect设置为“真”,在每次事务结束后驱动程序是否应尝试再连接?

No

false

3.0.10

roundRobinLoadBalance

启用了autoReconnect而且failoverReadonly为“假”时,是否应按照循环方式挑选要连接的主机?

No

false

3.1.2

queriesBeforeRetryMaster

出现故障切换(使用多主机故障切换)并返回主机之前发出的查询数。无论首先满足了哪个条件,“queriesBeforeRetryMaster”或“secondsBeforeRetryMaster”,均会再次与主机进行连接。默认值为“50”。

No

50

3.0.2

secondsBeforeRetryMaster

出现故障切换后,在尝试再次连接到主服务器之前,驱动程序应等待的时间? 无论首先满足了哪个条件,“queriesBeforeRetryMaster”或“secondsBeforeRetryMaster”,均会再次与主机进行连接。单位为秒,默认值为30。

No

30

3.0.2

enableDeprecatedAutoreconnect

自3.2版开始,自动再连接功能受到冷落,在3.3版中将删除该功能。将该属性设置为“真”可禁止检查配置的特性。

No

false

3.2.1

Security(安全)

allowMultiQueries

在一条语句中,允许使用“;”来分隔多条查询(真/假,默认值为“假”)。

No

false

3.1.1

useSSL

与服务器进行通信时使用SSL(真/假),默认值为“假”。

No

false

3.0.2

requireSSL

要求SSL连接,useSSL=true? 默认值为“假”。

No

false

3.1.0

allowUrlInLocalInfile

驱动程序在是“LOAD DATA LOCAL INFILE”语句中否允许URL?

No

false

3.1.4

paranoid

采取措施,防止在错误信息中泄漏敏感信息,并可可能时清除保存敏感数据的数据结构? 默认值为“假”。

No

false

3.0.1

Performance Extensions(性能扩展)

metadataCacheSize

如果将cacheResultSetMetaData设置为“真”,对cacheResultSetMetadata的查询次数(默认值为50)。

No

50

3.1.1

prepStmtCacheSize

如果允许预处理语句缓冲功能,应缓冲处理多少条预处理语句?

No

25

3.0.10

prepStmtCacheSqlLimit

如果允许预处理语句缓冲功能,驱动程序将执行解析缓冲处理的最大SQL是什么?

No

256

3.0.10

maintainTimeStats

驱动程序是否应维持各种内部定时器,以允许空闲时间计算,以及与服务器的连接失败时允许提供更详细的错误消息? 将该属性设置为“假”,对于每次查询,至少能减少两次对System.getCurrentTimeMillis()的调用。

No

true

3.1.9

blobSendChunkSize

组块,当通过ServerPreparedStatements发送BLOB/CLOB时使用。

No

1048576

3.1.9

cacheCallableStmts

驱动程序是否应对CallableStatements的解析过程执行缓冲处理。

No

false

3.1.2

cachePrepStmts

驱动程序是否应对客户端预处理语句的PreparedStatements的解析过程执行缓冲处理,是否应检查服务器端预处理语句的适用性以及服务器端预处理语句本身?

No

false

3.0.10

cacheResultSetMetadata

驱动程序是否应对用于Statements和PreparedStatements的ResultSetMetaData执行缓冲处理? 要求 JDK-1.4+,真/假,默认为“假”。

No

false

3.1.1

cacheServerConfiguration

驱动程序是否应根据每条URL对“HOW VARIABLES”和“SHOW COLLATION”的结果执行缓冲处理?

No

false

3.1.5

dontTrackOpenResources

JDBC规范要求驱动程序自动跟踪和关闭资源,但是,如果你的应用程序不能明确调用作用在语句或结果集上的close(),可能会导致内存泄漏。将该属性设置为“真”,可放宽该限制,对于某些应用程序,会提供更高的内存效率。

No

false

3.1.7

dynamicCalendars

需要时,驱动程序是否应检索默认日历,或根据连接/会话对其进行缓冲处理?

No

false

3.1.5

elideSetAutoCommits

如果使用MySQL-4.1或更高版本,当服务器的状态与Connection.setAutoCommit(boolean)请求的状态不匹配时,驱动程序是否仅应发出“set autocommit=n”查询?

No

false

3.1.3

holdResultsOpenOverStatementClose

驱动程序是否应按照JDBC规范的要求关闭Statement.close()上的结果集?

No

false

3.1.7

locatorFetchBufferSize

如果将“emulateLocators”配置为“真”,当获取关于getBinaryInputStream的BLOB数据时,缓冲区的大小应是多少?

No

1048576

3.2.1

useFastIntParsing

是否使用内部“String->Integer”转换子程序来避免创建过多对象?

No

true

3.1.4

useLocalSessionState

驱动程序是否应引用autocommit的内部值,以及由Connection.setAutoCommit()和Connection.setTransactionIsolation()设置的事务隔离,而不是查询数据库?

No

false

3.1.7

useNewIO

驱动程序是否应将java.nio.* interfaces用于网络通信(真/假),默认为“假”。

No

false

3.1.0

useReadAheadInput

从服务器读取数据时,是否使用较新的、优化的非成组缓冲输入流?

No

true

3.1.5

Debuging/Profiling(调试/仿形)

logger

实现了com.mysql.jdbc.log.Log的类的名称,com.mysql.jdbc.log.Log用于记录消息(默认为“com.mysql.jdbc.log.StandardLogger”,它会将日志记录到STDERR)。

No

com.mysql.jdbc.log.StandardLogger

3.1.1

profileSQL

跟踪查询以及它们对已配制记录器的执行/获取次数(真/假),默认为“假”。

No

false

3.1.0

reportMetricsIntervalMillis

如果允许“gatherPerfMetrics”,记录它们的频率是多少(单位毫秒)?

No

30000

3.1.2

maxQuerySizeToLog

调试或仿形时,控制将记录的查询的最大长度/大小。

No

2048

3.1.3

packetDebugBufferSize

当“enablePacketDebug”为“真”时,需要保留的最大信息包数目。

No

20

3.1.3

slowQueryThresholdMillis

如果允许“logSlowQueries”,在将查询记录为“慢”之前的查询时间是多少(毫秒)?

No

2000

3.1.2

useUsageAdvisor

驱动程序是否应发出“使用情况”警告,就DBC和MySQL Connector/J的恰当和高效使用给出建议(真/假,默认为“假”)?

No

false

3.1.1

autoGenerateTestcaseScript

驱动程序是否应将正在执行的SQL(包括服务器端预处理语句)转储到STDERR?

No

false

3.1.9

dumpQueriesOnException

驱动程序是否应将发送至服务器的查询内容转储到SQLExceptions中?

No

false

3.1.3

enablePacketDebug

允许时,将保留“packetDebugBufferSize”信息包的环形缓冲区,并当在驱动程序代码的关键区域抛出异常时进行转储。

No

false

3.1.3

explainSlowQueries

如果允许了“logSlowQueries”,驱动程序是否应在服务器上自动发出“EXPLAIN”,并以WARN级别将结果发送给配置好的日志?

No

false

3.1.2

logSlowQueries

是否要记录时间长于“slowQueryThresholdMillis”的查询?

No

false

3.1.2

traceProtocol

是否应记录跟踪级网络协议?

No

false

3.1.2

Miscellaneous(其他)

useUnicode

处理字符串时,驱动程序是否应使用Unicode字符编码? 仅应在驱动程序无法确定字符集映射,或你正在强制驱动程序使用MySQL不是固有支持的字符集时(如UTF-8)才应使用。真/假,默认为“真”。

No

false

1.1g

characterEncoding

如果“useUnicode”被设置为“真”,处理字符串时,驱动程序应使用什么字符编码? 默认为“autodetect”。

No

 

1.1g

characterSetResults

字符集,用于通知服务器以何种字符集返回结果。

No

 

3.0.13

connectionCollation

如果设置了它,将通知服务器通过“set collation_connection”使用该校对。

No

 

3.0.13

sessionVariables

以逗号隔开的“名称/值”对列表,当驱动程序建立了连接后,以“SET SESSION ...”的方式将其发送给服务器。

No

 

3.1.8

allowNanAndInf

驱动程序是否应在PreparedStatement.setDouble()中允许NaN或+/- INF值?

No

false

3.1.5

autoDeserialize

驱动程序是否应自动检测并串并转换保存在BLOB字段中的对象?

No

false

3.1.5

capitalizeTypeNames

是否将DatabaseMetaData中的类型名转换为大写? 通常仅在使用WebObjects时有用,真/假。默认为“假”。

No

false

2.0.7

clobberStreamingResults

这会使“流式”结果集被自动关闭,如果在所有数据尚未从服务器中读取完之前,执行了另一查询,正在从服务器流出的任何未完成数据均将丢失。

No

false

3.0.9

continueBatchOnError

如果一条语句失败,驱动程序是否应继续处理批命令? JDBC规范允许任何一种方式(默认为“真”)。

No

true

3.0.3

createDatabaseIfNotExist

如果不存在,创建URL中给定的数据库。假定用户具有创建数据库的权限。

No

false

3.1.9

emptyStringsConvertToZero

驱动程序是否应允许从空字符串字段到数值“0”的转换?

No

true

3.1.8

emulateLocators

N/A

No

false

3.1.0

emulateUnsupportedPstmts

驱动程序是否应检测不被服务器支持的预处理语句,并用客户端模拟版替换它们?

No

true

3.1.7

ignoreNonTxTables

是否忽略关于回退的非事务表? 默认值为“假”。

No

false

3.0.9

jdbcCompliantTruncation

连接到支持告警的服务器时(MySQL 4.1.0和更高版本),当按照JDBC的要求截短数据时,驱动程序是否应抛出java.sql.DataTruncation异常?

No

true

3.1.2

maxRows

返回的最大行数(0,默认值表示返回所有行)。

No

-1

all versions

noDatetimeStringSync

不保证ResultSet.getDatetimeType().toString().equals(ResultSet.getString()。

No

false

3.1.7

nullCatalogMeansCurrent

当DatabaseMetadataMethods请求“目录”参数时,值“Null”是否意味着使用当前目录? 它不兼容JDBC,但符合驱动程序早期版本的传统行为。

No

true

3.1.8

nullNamePatternMatchesAll

接受*pattern参数的DatabaseMetaData方法是否应将null按对待“%”的相同方式处理(不兼容JDBC,但驱动程序的早期版本能接受与规范的这类偏离)。

No

true

3.1.8

pedantic

严格遵守JDBC规范。

No

false

3.0.0

relaxAutoCommit

如果驱动程序所连接的MySQL服务器的版本不支持事务,仍允许调用commit()、rollback()和setAutoCommit()?真/假,默认为“假”。

No

false

2.0.13

retainStatementAfterResultSetClose

调用ResultSet.close()后,驱动程序是否应将语句引用保存在结果集中? 在JDBC-4.0后,与JDBC不兼容。

No

false

3.1.11

rollbackOnPooledClose

当连接池中的逻辑连接关闭时,驱动程序是否应发出rollback()?

No

true

3.0.15

runningCTS13

允许在Sun与JDBC兼容的testsuite 1.3版中处理缺陷。

No

false

3.1.7

serverTimezone

覆盖时区的检测/映射。当服务器的时区为映射到Java时区时使用。

No

 

3.0.2

strictFloatingPoint

仅在兼容性测试的早期版本中使用。

No

false

3.0.0

strictUpdates

驱动程序是否应对可更新结果集进行严格检查(选择所有的主键)?真/假,默认为“真”。

No

true

3.0.4

tinyInt1isBit

驱动程序是否应将数据类型TINYINT(1)当作BIT类型对待?创建表时,服务器会执行BIT -> TINYINT(1)操作。

No

true

3.0.16

transformedBitIsBoolean

如果驱动程序将TINYINT(1)转换为不同的类型,为了与MySQL-5.0兼容,驱动程序是否应使用BOOLEAN取代BIT?这是因为MySQL-5.0具有BIT类型。

No

false

3.1.9

ultraDevHack

由于UltraDev已损坏,并为所有语句发出了prepareCall(),需要时,是否要为prepareCall()创建PreparedStatements?

真/假,默认值为“假”。

No

false

2.0.3

useHostsInPrivileges

在DatabaseMetaData.getColumn/TablePrivileges()中为用户添加“@hostname”。真/假,默认为“真”。

No

true

3.0.2

useOldUTF8Behavior

与4.0和更早版本的服务器进行通信时,使用UTF-8。

No

false

3.1.6

useOnlyServerErrorMessages

对服务器返回的错误消息,不事先设定“标准的”SQLState错误消息。

No

true

3.0.15

useServerPrepStmts

如果服务器支持,是否使用服务器端预处理语句? 默认值为“真”。

No

true

3.1.0

useSqlStateCodes

使用SQL标准状态码取代“传统的”X/Open/SQL状态码,真/假,默认为“真”。

No

true

3.1.3

useStreamLengthsInPrepStmts

是否采用PreparedStatement/ResultSet.setXXXStream()方法调用中的流长度参数?真/假,默认为“真”。

No

true

3.0.2

useTimezone

是否在客户端和服务器时区间转换时间/日期类型(真/假,默认为“假”)?

No

false

3.0.2

useUnbufferedInput

不使用BufferedInputStream来从服务器读取数据。

No

true

3.0.11

yearIsDateType

JDBC驱动程序是否应将MySQL类型“YEAR”当作java.sql.Date或SHORT对待?

No

true

3.1.9

zeroDateTimeBehavior

当驱动程序遇到全由0组成的DATETIME值时,应出现什么?MySQL使用它来表示无效日期。有效值是“exception”、“round”和“convertToNull”。

No

exception

3.1.4

通过“socketFactory”属性,使用NamedPipeSocketFactory,在Windows NT/2000/XP平台上,通过命名管道,Connector/J也支持对MySQL的访问。如果不使用namedPipePath属性,将使用\\.\pipe\MySQL的默认值。如果使用NamedPipeSocketFactory,将忽略JDBC url中的主机名和端口号。

在URL中添加下述属性可启用NamedPipeSocketFactory

 

socketFactory=com.mysql.jdbc.NamedPipeSocketFactory

命名管道仅能当连接到位于相同物理机器上的MySQL时才能正常工作,该机器上应使用了JDBC驱动程序。在简单的性能测试中,命名管道的访问速度比标准的TCP/IP访问块30~50%。

使用com.mysql.jdbc.NamedPipeSocketFactorycom.mysql.jdbc.StandardSocketFactory中的示例代码,可创建你自己的套接字代理。

26.3.3.2. JDBC API实施说明

MySQL Connector/J通过了Sun JDBC兼容测试套件公共版中的所有测试。但是,在很多场合下,对于应如何实施特定的功能,JDBC规范并未给出明确的规定,或者说,该规范允许有一定的实施范围。

在本节中,就特定实施方案将如何影响MySQL Connector/J的使用方式,给出了接口层面上的详细介绍。

·         Blob

Blob实施不允许“原地”调整(它们是“副本”,正如DatabaseMetaData.locatorsUpdateCopies()方法所指明的那样)。因此,应使用对应的PreparedStatement.setBlob()或ResultSet.updateBlob()(对于可更新结果集)方法,将变化保存到数据库中。

自Connector/J version 3.1.0开始,通过在JDBC URL中添加属性“emulateLocators=true”,能够使用定位器模拟Blob。随后,必须使用带有列值的列别名,在你编写的用于检索Blob的SELECT中,将列值设为Blob列的世纪名称。SELECT还必须仅引用1个表,该表必须有1个主键,而且SELECT必须涵盖构成主键的所有列。随后,驱动程序将延期加载实际的Blob数据,直至检索了Blob并在其上调用了检索方法为止(getInputStream(), getBytes(),等)。

·         CallableStatement

自Connector/J 3.1.1开始,当通过CallableStatement接口连接到MySQL 5.0或更高版本时,可支持存储程序。目前,不支持CallableStatement的getParameterMetaData()方法。

·         Clob

Clob实施不允许“原地”调整(它们是“副本”,正如DatabaseMetaData.locatorsUpdateCopies()方法所指明的那样)。因此,应使用PreparedStatement.setClob()方法将变更保存到数据库中。JDBC API没有ResultSet.updateClob()方法。

·         Connection

与MM.MySQL的早期版本不同,“isClosed()”不会对服务器即行Ping操作以确定服务器是否有效。按照JDBC规范,如果在连接上调用了“closed()”,它仅返回“真”。如果需要确定连接是否依然有效,应发出简单查询,如“SELECT 1”。如果连接不再有效,驱动程序将抛出异常。

·         DatabaseMetaData

对于外键信息(getImported/ExportedKeys()和getCrossReference()),仅在“InnoDB”类性的表中可用。但是,驱动程序会使用“SHOW CREATE TABLE”来检索该信息,因此,当其他表类型支持外键时,驱动程序也能支持它们。

·         Driver

·         PreparedStatement

PreparedStatements是由驱动程序实现的,这是应为MySQL未提供预处理语句功能。出于该原因,驱动程序不实施getParameterMetaData()或getMetaData(),这是因为,它要求驱动程序在客户端上具有完整的SQL语法分析程序。

从3.1.0版MySQL Connector/J开始,当服务器支持时,将使用服务器端预处理语句和“二进制编码”的结果集。

使用带有“large”参数(这类参数是通过setBinaryStream()、setAsciiStream()、setUnicodeStream()、setBlob()或setClob()设置的)的服务器端预处理语句时应谨慎。如果打算再次执行已将任何“large”参数更改为非“large”参数的语句,需要调用clearParameters(),并再次设置所有参数。其原因如下:

o        设置了参数时,驱动程序会将“large”数据“out-of-band”发送给服务器端的预处理语句(执行预处理语句之前)。

o        一旦完成,将关闭用于读取客户端上数据的流(根据JDBC规范),而且不能再次读取流。

o        如果参数从“large”变为非“large”,驱动程序必须复位预处理语句的服务器端状态,以便允许已更改的参数区带以前的“large”值。这将删除已发送给服务器的所有“large”数据,因而需要通过setBinaryStream()、setAsciiStream()、setUnicodeStream()、setBlob()或setClob()方法再次发送数据。

因而,如果你打算将参数类型更改为非“large”类型,必须调用clearParameters(),并在重新执行预处理语句之前再次设置预处理语句的所有参数。

·         ResultSet

在默认情况下,ResultSets(结果集)是可完全检索的,并被保存在内存中。对于大多数情况,这是最有效的操作方式,而且还应归因于更容易实施的MySQL网络协议设计。如果你正在处理具有大量行或大数据的ResultSets,而且无法在JVM内为所需内存分配大量空间,可以通知驱动程序以“流”方式返回结果,一次一行。

要想允许该功能,需要以下述方式创建1个语句实例:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
              java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

正向、只读结果集,以及Integer.MIN_VALUE的组合用于指示驱动程序以“流”方式按行处理结果集。此后,对于该语句创建的结果集,将按行检索。

对于该方式,有一些需注意的事项。能够在连接上发出任何其他查询之前,应读取结果集中的所有行(或关闭结果集),否则将抛出异常。

能够释放这些锁定语句(无论它们是MyISAM表级锁定,还是某些其他存储引擎如InnoDB中的行级锁定)的最早时刻是完成语句时。

如果语句在事务的范围内,当事务完成后将释放锁定(它意味着语句需首先完成)。与大多数其他数据库一样,在读取了语句上所有的未决结果集或关闭了语句的活动结果集之前,语句不会结束。

因此,如果正在使用“流式”结果,如果希望保持对特定表的同时访问,而这些表被生成结果集的语句所引用,就应尽快地处理“流式”结果。

·         ResultSetMetaData

仅当使用MySQL服务器4.0或更高版本时,“isAutoIncrement()”方法才能正确工作。

·         Statement

使用版本低于3.2.1的JDBC驱动程序,而且所连接的服务器版本低于5.0.3时,除了像前面介绍的那样切换结果集外,“setFetchSize()”方法不起作用。

MySQL不支持SQL光标,而且JDBC驱动程序也不能模拟它们,因此“setCursorName()”没有效果。

26.3.3.3. Java,JDBC和MySQL类型

MySQL Connector/J在处理MySQL数据类型和Java数据类型的转换处理方面十分灵活。

尽管可能会出现舍入、溢出或精度损失,当在通常情况下,能够将任何MySQL数据类型转换为java.lang.String,并能将任何数值类型转换为Java数值类型。

从Connector/J 3.1.0开始,按照JDBC规范的要求,JDBC驱动程序将发出警告或抛出DataTruncation异常,除非通过使用“jdbcCompliantTruncation”属性并将其设为“假”,对连接进行相应配置取消了前述要求。

在下面的表格中,列出能可靠工作的转换:

表26.2. 转换表

下述MySQL数据类型

总能转换为下述Java类型

CHAR, VARCHAR, BLOB, TEXT, ENUM, and SET

java.lang.String, java.io.InputStream, java.io.Reader, java.sql.Blob, java.sql.Clob

FLOAT, REAL, DOUBLE PRECISION, NUMERIC, DECIMAL, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT

java.lang.String, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Double, java.math.BigDecimal

注释:

与希望转换的MySQL数据类型相比,如果选择了精度较低的Java数值类型,可能会出现舍入、溢出或精度损失。

DATE, TIME, DATETIME, TIMESTAMP

java.lang.String, java.sql.Date, java.sql.Timestamp

在MySQL类型和Java类型之间,ResultSet.getObject()方法采用了下述类型转换方式,在可能的情况下遵从JDBC规范:

表26.3. 用于ResultSet.getObject()的MySQL类型和Java类型

MySQL类型名称

Java类返回

BIT(1) (new in MySQL-5.0)

java.lang.Boolean

BIT( > 1) (new in MySQL-5.0)

byte[]

TINYINT

java.lang.Boolean,如果将配置属性tinyInt1isBit”设为“真”(默认值),并将存储大小设为“1”;或java.lang.Integer,如果不是的话。

BOOL , BOOLEAN

请参见上面的TINYINT,它们目前是TINYINT(1)的别名。

SMALLINT[(M)] [UNSIGNED]

java.lang.Integer(无论是否为UNSIGNED

MEDIUMINT[(M)] [UNSIGNED]

java.lang.Integer(无论是否为UNSIGNED

INT,INTEGER[(M)] [UNSIGNED]

java.lang.Integer,如果是UNSIGNEDjava.lang.Long

BIGINT[(M)] [UNSIGNED]

java.lang.Long,如果是UNSIGNEDjava.math.BigInteger

FLOAT[(M,D)]

java.lang.Float

DOUBLE[(M,B)]

java.lang.Double

DECIMAL[(M[,D])]

java.math.BigDecimal

DATE

java.sql.Date

DATETIME

java.sql.Timestamp

TIMESTAMP[(M)]

java.sql.Timestamp

TIME

java.sql.Time

YEAR[(2|4)]

java.sql.Date(日期设为21日晚上2点)

CHAR(M)

java.lang.String(除非列的字符集是BINARY),然后返回字节[]

VARCHAR(M) [BINARY]

java.lang.String(除非列的字符集是BINARY),然后返回字节[]

BINARY(M)

byte[]

VARBINARY(M)

byte[]

TINYBLOB

byte[]

TINYTEXT

java.lang.String

BLOB

byte[]

TEXT

java.lang.String

MEDIUMBLOB

byte[]

MEDIUMTEXT

java.lang.String

LONGBLOB

byte[]

LONGTEXT

java.lang.String

ENUM('value1','value2',...)

java.lang.String

SET('value1','value2',...)

java.lang.String

26.3.3.4. 使用字符集和Unicode

对于从JDBC驱动程序发往服务器的所有字符串,均将自动地从固有放热Java Unicode形式转换为客户端字符编码,包括通过Statement.execute()Statement.executeUpdate()和Statement.executeQuery()发出的所有查询,以及除了用setBytes()、setBinaryStream()setAsiiStream()setUnicodeStream()setBlob()排除的参试之外的所有PreparedStatementCallableStatement参数

在MySQL服务器4.1之前,Connector/J支持每连接单一字符编码,能够从服务器配置自动检测到它,也能由用户通过使用useUnicodecharacterEncoding属性配置它。

从MySQL服务器4.1版起,Connector/J支持客户端和服务器之间的但以字符编码,以及针对结果集中从服务器返回至客户端的数据的任意数目字符编码。

连接时将自动检测客户端和服务器之间的字符编码。对于由驱动程序使用的编码来说,它是在服务器上通过使用配置变量“character_set”(低于4.1.0的服务器版本)和“character_set_server”(4.1.0和更高的服务器版本)指定的。更多信息,请参见MySQL服务器手册中的服务器字符集和校对一节。

要想覆盖客户端上的自动检测编码功能,可在用于连接到服务器的URL中使用“characterEncoding”属性。

在客户端上指定字符编码时,应使用Java风格名称。在下面的表格中,列出了用于MySQL字符集的Java风格名称:

表26.4. MySQL对Java编码名称的翻译

MySQL字符集名称 Java风格字符编码名称
usa7 US-ASCII
big5 Big5
gbk GBK
sjis SJIS
gb2312 EUC_CN
ujis EUC_JP
euc_kr EUC_KR
latin1 ISO8859_1
latin1_de ISO8859_1
german1 ISO8859_1
danish ISO8859_1
latin2 ISO8859_2
czech ISO8859_2
hungarian ISO8859_2
croat ISO8859_2
greek ISO8859_7
hebrew ISO8859_8
latin5 ISO8859_9
latvian ISO8859_13
latvian1 ISO8859_13
estonia ISO8859_13
dos Cp437
pclatin2 Cp852
cp866 Cp866
koi8_ru KOI8_R
tis620 TIS620
win1250 Cp1250
win1250ch Cp1250
win1251 Cp1251
cp1251 Cp1251
win1251ukr Cp1251
cp1257 Cp1257
macroman MacRoman
macce MacCentralEurope
utf8 UTF-8
ucs2 UnicodeBig

警告

不要用Connector/J发出查询“set names”,这是因为驱动程序不会检测已变化的字符集,而是会继续使用在初始连接设置中检测到的字符集。

为了允许从客户端发出的多个字符集,应使用“UTF-8”编码,方式是,将utf8配置为默认的服务器字符集,或通过“characterEncoding”属性配置JDBC驱动程序以使用“UTF-8”。

26.3.3.5. 使用SSL进行安全连接

MySQL Connector/J中的SSL能够对JDBC驱动程序和服务器之间传输的所有数据进行加密(除了初始握手数据)。启用SSL会导致性能损失,体现在查询时间将增加35~50%,具体情况取决于查询的大小以及返回的数据量。

要想使SSL支持能够工作,必须满足下述要求:

·         包含JSSE(Java安全套接字扩展)的JDK,如JDK-1.4.1或更高版本。SSL目前不能与能够为其添加JSSE的JDK一起工作,如JDK-1.2.x或JDK-1.3.x,原因在于下述JSSE缺陷:http://developer.java.sun.com/developer/bugParade/bugs/4273544.html

·         支持SSL并已编译和配置了该功能的MySQL服务器,如MySQL-4.0.4和更高版本,请参见:http://www.mysql.com/doc/en/Secure_connections.html

·         客户端证书(在本节稍后介绍)。

首先,需要将MySQL服务器CA证书导入到Java truststore。在MySQL源码分发版的“SSL”子目录下给出了1个示例MySQL服务器CA证书。SSL将使用它来确定是否与安全MySQL服务器进行通信。

要想使用Java的“keytool”在当前目录下创建truststore,并导入服务器的CA证书(“cacert.pem”),可采取下述方式(假定“keytool”位于路径中。它位于JDK或JRE的“bin”子目录下):

shell> keytool -import -alias mysqlServerCACert -file cacert.pem -keystore truststore
        

Keytool将给出下述响应信息:

Enter keystore password:  *********
Owner: EMAILADDRESS=walrus@example.com, CN=Walrus, O=MySQL AB, L=Orenburg, ST=Some
-State, C=RU
Issuer: EMAILADDRESS=walrus@example.com, CN=Walrus, O=MySQL AB, L=Orenburg, ST=Som
e-State, C=RU
Serial number: 0
Valid from: Fri Aug 02 16:55:53 CDT 2002 until: Sat Aug 02 16:55:53 CDT 2003
Certificate fingerprints:
         MD5:  61:91:A0:F2:03:07:61:7A:81:38:66:DA:19:C4:8D:AB
         SHA1: 25:77:41:05:D5:AD:99:8C:14:8C:CA:68:9C:2F:B8:89:C3:34:4D:6C
Trust this certificate? [no]:  yes
Certificate was added to keystore

随后,需要生成客户端证书,以便MySQL服务器知道它正与安全客户端进行通信:

 shell> keytool -genkey -keyalg rsa -alias mysqlClientCertificate -keystore keystore 

Keytool将给出下述提示信息,并在当目录下创建名为“keystore”的密钥存储器。

你应使用与具体情况相适应的新作出响应:

Enter keystore password:  *********
What is your first and last name?
  [Unknown]:  Matthews
What is the name of your organizational unit?
  [Unknown]:  Software Development
What is the name of your organization?
  [Unknown]:  MySQL AB
What is the name of your City or Locality?
  [Unknown]:  Flossmoor
What is the name of your State or Province?
  [Unknown]:  IL
What is the two-letter country code for this unit?
  [Unknown]:  US
Is <CN=Matthews, OU=Software Development, O=MySQL AB,
 L=Flossmoor, ST=IL, C=US> correct?
  [no]:  y
 
输入<mysqlClientCertificate>的密码
        如果与keystore的密码相同,按回车):

最后,要想使JSSE能够使用你生成的keystore和truststore,启动JVM时,需要设置下述系统属性,用你所创建的keystore文件完整路径替换“path_to_keystore_file”,用你所创建的truststore文件完整路径替换“path_to_truststore_file”,并为每个属性使用恰当的密码值。

-Djavax.net.ssl.keyStore=path_to_keystore_file
-Djavax.net.ssl.keyStorePassword=*********
-Djavax.net.ssl.trustStore=path_to_truststore_file
-Djavax.net.ssl.trustStorePassword=********* 

此外,还需要在用于MySQL Connector/J的连接参数中将“useSSL”设置为“真”,方法是,在URL中添加“useSSL=true”,或在准备传递给DriverManager.getConnection()的java.util.Properties实例中将“useSSL”设置为“真”。

你可以打开JSSE调试功能能够,测试SSL是否工作(详情如下),并查找下述关键事件:

...
 *** ClientHello, v3.1
 RandomCookie:  GMT: 1018531834 bytes = { 199, 148, 180, 215, 74, 12, 54, 244, 0, 168, 55, 103, 215, 64, 16, 138, 225, 190, 132, 153, 2, 217, 219, 239, 202, 19, 121, 78 }
 Session ID:  {}
 Cipher Suites:  { 0, 5, 0, 4, 0, 9, 0, 10, 0, 18, 0, 19, 0, 3, 0, 17 }
 Compression Methods:  { 0 }
 ***
 [write] MD5 and SHA1 hashes:  len = 59
 0000: 01 00 00 37 03 01 3D B6   90 FA C7 94 B4 D7 4A 0C  ...7..=.......J.
 0010: 36 F4 00 A8 37 67 D7 40   10 8A E1 BE 84 99 02 D9  6...7g.@........
 0020: DB EF CA 13 79 4E 00 00   10 00 05 00 04 00 09 00  ....yN..........
 0030: 0A 00 12 00 13 00 03 00   11 01 00                 ...........
 main, WRITE:  SSL v3.1 Handshake, length = 59
 main, READ:  SSL v3.1 Handshake, length = 74
 *** ServerHello, v3.1
 RandomCookie:  GMT: 1018577560 bytes = { 116, 50, 4, 103, 25, 100, 58, 202, 79, 185, 178, 100, 215, 66, 254, 21, 83, 187, 190, 42, 170, 3, 132, 110, 82, 148, 160, 92 }
 Session ID:  {163, 227, 84, 53, 81, 127, 252, 254, 178, 179, 68, 63, 182, 158, 30, 11, 150, 79, 170, 76, 255, 92, 15, 226, 24, 17, 177, 219, 158, 177, 187, 143}
 Cipher Suite:  { 0, 5 }
 Compression Method: 0
 ***
 %% Created:  [Session-1, SSL_RSA_WITH_RC4_128_SHA]
 ** SSL_RSA_WITH_RC4_128_SHA
 [read] MD5 and SHA1 hashes:  len = 74
 0000: 02 00 00 46 03 01 3D B6   43 98 74 32 04 67 19 64  ...F..=.C.t2.g.d
 0010: 3A CA 4F B9 B2 64 D7 42   FE 15 53 BB BE 2A AA 03  :.O..d.B..S..*..
 0020: 84 6E 52 94 A0 5C 20 A3   E3 54 35 51 7F FC FE B2  .nR..\ ..T5Q....
 0030: B3 44 3F B6 9E 1E 0B 96   4F AA 4C FF 5C 0F E2 18  .D?.....O.L.\...
 0040: 11 B1 DB 9E B1 BB 8F 00   05 00                    ..........
 main, READ:  SSL v3.1 Handshake, length = 1712
 ...

设置了下述系统属性时,JSSE可提供调试功能(为STDOUT):-Djavax.net.debug=all。它用于设定要使用的keystores和truststores,以及在SSL握手和证书交换过程中将出现什么。当你尝试进行SSL连接时,如果打算确定不能工作的部分,该设置十分有用。

26.3.3.6. 使用主/从复制和ReplicationConnection

从Connector/J 3.1.7开始,我们提供了1个驱动程序变体,它能自动发出读/写主服务器的查询,或根据Connection.getReadOnly()的状态对从主机进行故障切换或循环负载平衡设置。

应用程序发出信号,通过调用Connection.setReadOnly(true)指明事务为只读的,该具有复制意识的连接将使用从连接之一,从连接是采用了循环方案的负载平衡per-vm(给定连接与从连接密切相关,除非在服务中删除了从连接)。如果你有1项写事务,或1项对时间敏感的读事务(记住,在MySQL中,复制是以异步方式进行的),请调用Connection.setReadOnly(false),将连接设置为非只读的,驱动程序会确保进一步的调用均将被发送到主MySQL服务器。驱动程序负责传播autocommit的当前状态,隔离级别,以及用于完成该负载平衡功能的所有连接之间的目录。

要想启用该该功能,在配置应用服务器的连接池时,或为独立应用程序创建JDBC驱动实例时,请使用“com.mysql.jdbc.ReplicationDriver”类。由于它能接受与标准MySQL JDBC驱动相同的URL格式,ReplicationDriver目前不能与基于java.sql.DriverManager的连接一起使用,除非它是用DriverManager注册的唯一MySQL JDBC驱动程序。

下面给出了一个简短的简单示例,介绍了如何在独立应用程序中使用ReplicationDriver的方法。

import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Properties;
 
import com.mysql.jdbc.ReplicationDriver;
 
public class ReplicationDriverDemo {
 
    public static void main(String[] args) throws Exception {
        ReplicationDriver driver = new ReplicationDriver();
 
        Properties props = new Properties();
 
        // We want this for failover on the slaves
        props.put("autoReconnect", "true");
 
        // We want to load balance between the slaves
        props.put("roundRobinLoadBalance", "true");
 
        props.put("user", "foo");
        props.put("password", "bar");
 
        //
        // Looks like a normal MySQL JDBC url, with a comma-separated list
        // of hosts, the first being the 'master', the rest being any number
        // of slaves that the driver will load balance against
        //
 
        Connection conn =
            driver.connect("jdbc:mysql://master,slave1,slave2,slave3/test",
                props);
 
        //
        // Perform read/write work on the master
        // by setting the read-only flag to "false"
        //
 
        conn.setReadOnly(false);
        conn.setAutoCommit(false);
        conn.createStatement().executeUpdate("UPDATE some_table ....");
        conn.commit();
 
        //
        // Now, do a query from a slave, the driver automatically picks one
        // from the list
        //
 
        conn.setReadOnly(true);
 
        ResultSet rs = conn.createStatement().executeQuery("SELECT a,b,c FROM some_other_table");
 
         .......
    }
}
关注编程学问公众号