背景
这两天在做数据同步项目的联调,测试过程中发现针对mysql的一些使用上存在一些问题,比如batch不起效果,编码问题,预编译失效等等。 这里总结一下,做一下记录,希望对遇到类似问题的有所帮助
内容
编码问题
官方文档: http://dev.mysql.com/doc/refman/4.1/en/connector-j-reference-charsets.html
网上针对mysql的中文编码问题,已经有不少文章进行介绍,大概步骤如下:
1. 设置my.cnf中, 设置default-character-set=utf8
2. 创建表时指定编码,create table {...} ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ;
3. 客户端链接url上,指定编码参数: useUnicode=true&characterEncoding=UTF-8
因为项目是做一个数据同步项目,所以需要处理的是客户端的编码问题(server端的编码会由DBA搞定),刚开始时没设置客户端链接参数,在程序中手工的将源库(GBK),转成了目标库(UTF-8)的编码,构造了特定编码的SQL。
但是用构造出来的UTF-8编码的string流,通过jdbcTemplate执行的时候,目标库中针对中文字符出现了乱码。
大致猜测应该是在driver层面没有正确的送出数据流到目标数据库上,具体编码处理代码如下:
类:com.mysql.jdbc.ConnectionImpl
方法: checkServerEncoding()
private void checkServerEncoding() throws SQLException {
if (getUseUnicode() && (getEncoding() != null)) { //位置1
// spec'd by client, don't map
return;
}
String serverEncoding = (String) this.serverVariables.get("character_set");
if (serverEncoding == null) {
// must be 4.1.1 or newer?
serverEncoding = (String) this.serverVariables.get("character_set_server");
}
String mappedServerEncoding = null;
if (serverEncoding != null) {
mappedServerEncoding = CharsetMapping
.getJavaEncodingForMysqlEncoding(serverEncoding.toUpperCase(Locale.ENGLISH), this);
}
//
// First check if we can do the encoding ourselves
//
if (!getUseUnicode() && (mappedServerEncoding != null)) {
SingleByteCharsetConverter converter = getCharsetConverter(mappedServerEncoding);
if (converter != null) { // we know how to convert this ourselves
setUseUnicode(true); // force the issue
setEncoding(mappedServerEncoding);
return;
}
}
}
说明:
1. 首先会校验useUnicode和characterEncoding参数的设置(即为url中的参数设置),如果有则直接返回,不去自动猜测db server的编码
2. 读取mysql variables数据,提取character_set和character_set_server的编码做为characterEncoding编码
3. 基于characterEncoding构造了SingleByteCharsetConverter进行编码转化,最终录入到目标库
原理搞清楚了,基本这编码问题也就很容易解决了。
1. check下mysql variables变量:
命令: show variables like 'character\_set\_%';
结果:
character_set_server编码为latin1 , 而我数据表的编码为utf-8,这也就难怪出现乱码了,最后设置下根据不同的数据表设置characterEncoding即可。
预编译问题
相关文章: http://blog.csdn.net/axman/article/details/6913527
具体的参数设置,这里面已经写的比较详细了,我就简单的从driver层面来给大家介绍下。
类:com.mysql.jdbc.ConnectionImpl
方法: initializePropsFromServer()
//
// Users can turn off detection of server-side prepared statements
//
if (getUseServerPreparedStmts() && versionMeetsMinimum(4, 1, 0)) {
this.useServerPreparedStmts = true;
if (versionMeetsMinimum(5, 0, 0) && !versionMeetsMinimum(5, 0, 3)) {
this.useServerPreparedStmts = false; // 4.1.2+ style prepared
// statements
// don't work on these versions
}
}
说明:
1. getUseServerPreparedStmts()主要是从connection properties中提取useServerPrepStmts变量的设置(useServerPrepStmts=true/false)
2. prepareStatement使用代码,也是在ConnectionImpl.prepareStatement方法中
- 针对特定的sql,CREATE TABLE/SET操作,不使用预编译
- prepStmtCacheSqlLimit长度限制,默认256。超过该长度后,不使用预编译
- cachePrepStmts设置是否对预编译使用local cache
- prepStmtCacheSize指定了local cache的大小,使用了LRU进行逐出
- 最后使用com.mysql.jdbc.ServerPreparedStatement和db server的建立映射
3. 如果不开启(useServerPrepStmts=false),使用com.mysql.jdbc.PreparedStatement进行本地SQL拼装,最后送到db上就是已经替换了?后的最终SQL
总结一下,注意几个参数即可:
- useServerPrepStmts=true/false
- prepStmtCacheSqlLimit=256
- cachePrepStmts=true/false
- prepStmtCacheSize=256
预编译cache在链接池层面都已经有类似的实现,可以不开启driver的cache参数。
可以通过命令: show global status like '%prepare%' , 查看db server端预编译的使用情况
批处理问题
mysql默认关闭了batch处理,需要设置rewriteBatchedStatements=true参数进行打开。
使用代码:com.mysql.jdbc.StatementImpl,com.mysql.jdbc.PreparedStatement的executeBatch()方法
最后
总结一下,主要是几个参数的使用:
BasicDataSource dbcpDs = new BasicDataSource();
dbcpDs.addConnectionProperty("useServerPrepStmts", "true");
dbcpDs.addConnectionProperty("rewriteBatchedStatements", "true");
dbcpDs.addConnectionProperty("characterEncoding", encoding);
- 大小: 27.5 KB
分享到:
相关推荐
在MySQL Connector/J 5.0.8中,以下几个方面是其主要知识点: 1. **JDBC接口**:JDBC是Java平台上的标准数据库访问接口,它提供了一套API,允许Java程序与各种关系型数据库进行通信。MySQL Connector/J实现了JDBC...
- 使用PreparedStatement预编译SQL语句,可以提高执行效率。 - 适当使用批处理(Batch Processing)提交多条SQL语句,减少网络通信次数。 - 通过设置连接池,如C3P0或HikariCP,可以重用数据库连接,减少资源消耗...
在源码中,关键类包括以下几个部分: - `com.mysql.jdbc.Connection`:代表数据库连接,它实现了`java.sql.Connection`接口,提供了如建立、管理和关闭连接的方法。 - `com.mysql.jdbc.Statement`和`...
了解这个驱动包,我们需要探讨以下几个核心知识点: 1. **JDBC**: JDBC是Java平台上的一个标准接口,它定义了如何在Java应用程序和数据库之间建立通信。通过JDBC,开发者可以编写通用的数据库访问代码,无需关心...
- MySQL Connector/J支持多种特性,如事务处理、批处理、预编译的SQL语句(PreparedStatement)、连接池等,这些功能可以提高应用程序的性能和可靠性。 - 不同的MySQL版本可能需要不同版本的JDBC驱动,因此在升级...
7. **兼容性与性能优化**:MySQL JDBC驱动不断更新以保持与最新MySQL版本的兼容性,同时提供性能优化选项,如使用`useServerPrepStmts=false`来禁用服务器端的预编译,以降低网络开销。 8. **SSL加密**:驱动支持...
在实际开发中,`mysql-connector-java`驱动不仅支持基本的SQL操作,还提供了高级功能,如事务处理、批处理、预编译的SQL语句(提高性能)、连接池支持等。此外,它还支持最新的MySQL特性,如存储过程、触发器、视图...
这个版本的驱动支持各种特性,包括批处理、预编译的SQL语句、存储过程的调用等,以提高性能和安全性。 与`mysql-connector-java-5.1.7-bin.jar`一同提供的`docs`文件夹可能包含该驱动的文档,这包括API参考、用户...
这个过程涉及到几个关键步骤和技术,包括理解SQL、使用Java的数据库连接器(JDBC)以及配置数据库连接参数。本篇文章将深入探讨如何使用Java通过AccessRemoteMySQLDB-API来实现这一目标。 首先,了解SQL是基础。SQL...
系统的实现主要包括以下几个模块:用户注册与登录、个人信息管理、联系人管理。用户注册时,信息通过Struts2提交到服务器,由Hibernate进行持久化存储。登录时,系统验证用户名和密码,通过Struts2跳转至相应页面。...
JDBC工作流程一般分为以下几个步骤: 1. 加载驱动:使用`Class.forName()`方法加载数据库驱动。 2. 获取连接:通过`DriverManager.getConnection()`方法建立与数据库的连接。 3. 创建Statement/PreparedStatement:...
- 动态SQL:使用PreparedStatement进行预编译的SQL,可以防止SQL注入并提高性能。 - 连接池:理解C3P0、DBCP或HikariCP等连接池的概念,它们能有效管理数据库连接,提高应用效率。 - 数据库事务:掌握ACID(原子性、...
通常情况下,通过JDBC连接数据库需要经历以下几个步骤: 1. **加载并注册JDBC驱动**:首先需要加载特定数据库厂商提供的JDBC驱动类,并将其注册到JDBC驱动管理器中。 2. **获取数据库连接**:通过DriverManager.get...
例如,DB2的URL是`jdbc:db2://localhost:5000/sample`,而MySQL的URL则是`jdbc:mysql://localhost/myDB`,并需要指定字符编码等参数。 值得注意的是,随着JDBC的发展,现在的驱动加载通常是自动的,不需要显式调用`...
3. **创建Statement或PreparedStatement**:`Statement`用于执行静态SQL语句,而`PreparedStatement`用于预编译SQL,提供性能优势和防止SQL注入。 4. **执行SQL**:调用`executeQuery()`或`executeUpdate()`执行SQL...
Ebean是一个针对Java平台的高效ORM(对象关系映射)框架,它的主要目标是提供简单、快速的数据访问和编码体验。ORM框架的核心功能是将数据库中的表映射为Java对象,使得开发者可以以面向对象的方式来操作数据库,而...
在MySQL数据库管理中,存储过程是一种预编译的SQL代码集合,用于执行特定任务或处理复杂的业务逻辑。在处理大量数据或频繁重复的查询时,存储过程可以提高性能,简化代码,并提供更好的安全性。然而,如果不进行适当...
PPT可能包括以下几个主要知识点: 1. **JDBC API概述**:介绍JDBC API的基本概念,包括JDBC驱动类型(Type 1至Type 4),以及如何在Java代码中加载和注册这些驱动。 2. **建立数据库连接**:讲解如何使用`...
5. **编译脚本和构建文件**:用于编译和运行项目的批处理或Makefile文件。 6. **测试用例**:可能包含测试数据和自动化测试脚本,用于验证系统的正确性。 综合以上分析,这个项目涵盖了多个IT领域的知识点,包括: ...
本课件主要涉及了MIS的技术基础,包括以下几个核心领域: 1. **计算机硬件技术**: - 计算机系统由硬件和软件两大部分组成。硬件包括运算器、控制器、存储器、输入设备和输出设备,这些构成了冯·诺依曼体系结构。...