记一下在 Spring + MyBatis 整合中遇到的问题以及解决方案
记一下在 Spring + MyBatis 整合中遇到的问题以及解决方案
org.springframework.jdbc.BadSqlGrammarException
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select seckill_id,name,number,start_time,end_time,create_time
from secki' at line 2
### The error may exist in file [D:\Code\Java\SecKill\target\classes\mapper\SecKillDao.xml]
### The error may involve org.seckill.dao.SecKillDao.queryById-Inline
### The error occurred while setting parameters
### SQL: use seckill; select seckill_id,name,number,start_time,end_time,create_time from seckill.seckill where seckill_id = ?
### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select seckill_id,name,number,start_time,end_time,create_time
from secki' at line 2
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select seckill_id,name,number,start_time,end_time,create_time
from secki' at line 2
这是我的报错信息,导致这个问题的原因有很多,但归根结底是 mapper 的 xml 中 SQL 语句的问题
- xml 中的 SQL 语句中的表名或者字段名含有 SQL 数据库的关键字,比如 ORDER , INSERT 之类的,这个时候要么改字段名(注意一般不要将字段名设置为关键字),要么把相应的字段名用 ` 引号括起来,表明这不是 SQL 关键字。
- 也有可能是属性注入失败的问题,关于属性注入失败的原因可能是注入字段的 #{PARANAME} 中的 PARANAME 名跟方法中的属性名不同,这里建议在声明方法时加上 @Param("name") 的方式命名属性,比如
int reduceNumber(@Param("secKillId") long secKillId,@Param("killTime") Date killTime);
但一般来说都不是这个问题^^
-
这个情况也是我遇到的问题,出错的代码如下:
<select id="queryById" resultType="SecKill" parameterType="long"> use seckill; select seckill_id,name,number,start_time,end_time,create_time from seckill <!-- 我的数据库名和表名都是 seckill --> where seckill_id = #{secKillId} </select>
我的 SQL 语句中有了分号,所以导致的 SQL 语法不对,解决办法是去掉分号,然后改写 SQL 语句为:
<select id="queryById" resultType="SecKill" parameterType="long"> # use seckill; select seckill_id,name,number,start_time,end_time,create_time from seckill.seckill where seckill_id = #{secKillId} </select>
这也说明了在 MyBatis 的 mapper.xml 文件中 SQL 语句不要有分号。
java.lang.IllegalStateException: Failed to load ApplicationContext
错误信息给的很明确:加载应用上下文失败,也就是加载某个配置文件失败。具体是哪个配置文件就需要看详细的错误信息了
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring/spring-dao.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [mybatis-config.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: The setting useColumnabel is not known. Make sure you spelled it correctly (case sensitive).
从这里可以看到是在初始化 sqlSessionFactory 的地方出了错,再往下面看就能看到具体的位置是 The setting useColumnabel is not known
也就是说拼写出错,这可能是由不熟悉配置文件的属性值或者马虎导致的。检查并查询官方文档更改为正确的拼写即可。
JDBC 驱动
这里顺带提一句,MySQL 数据库的 JDBC 驱动地址不再是 com.mysql.jdbc.Driver
(虽然也能用),而是新的 com.mysql.cj.jdbc.Driver
org.mybatis.spring.MyBatisSystemException
详细信息:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Connections could not be acquired from the underlying database!
### The error may exist in file [D:\Code\Java\SecKill\target\classes\mapper\SecKillDao.xml]
### The error may involve org.seckill.dao.SecKillDao.queryById
### The error occurred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Connections could not be acquired from the underlying database!
错误信息显示是获取数据库连接出错,这个错误出现的也有几种情况
- 顺着上面的错误信息再往下找能找到
Caused by: java.sql.SQLSyntaxErrorException: Unknown database 'seckil'
,可以发现数据库连接池 jdbcUrl 的属性值配置本身就有问题 ,比如少写了个啥字母之类的,这个不必多说检查出来,改正确就行了 - 数据库连接地址没问题,但是还是报了这个错,这是我遇到的问题。老规矩,继续往下找,错误信息越往后位置越精确!
Caused by: java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specific time zone value if you want to utilize time zone support.
然后发现这么个错,说服务器的时区配置未被认可或者超过了一个时区的数量限制,你必须配置 JDBC 或者 服务器的 serverTimezone 属性中的任何一个,本来的代码是 jdbcUrl = jdbc:mysql://localhost:3306/seckill
压根儿就没配置时区,报错。解决方案:
jdbcUrl = jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC 解决时区和中文乱码问题
java.lang.ClassNotFoundException: "com.mysql.cj.jdbc.Driver"
先上数据库参数配置代码
# 数据库驱动
driver = "com.mysql.cj.jdbc.Driver"
# 数据库连接
# jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC 解决时区和中文乱码问题
jdbcUrl = jdbc:mysql://localhost:3306/seckill?serverTimezone=UTC
# USER_NAME
user_name = root
# PWD
pwd = 201313
这个问题就是属性值写法的问题了,properties 里面的所有数据都是以键值对的方式进行存储的,value 值都不用双引号,并且后面不能跟空格,输完直接回车
java.lang.AbstractMethodError:Methodcom/mchange/v2/c3p0/impl/NewProxyResultSet.isClosed()Z is abstract
出现了这个错,本应被废弃的 isClose() 被调用了!解决方案就是不用就可以了,isClose() 方法在 c3p0 version 0.9.2.x 之后的版本就被废弃了,所以只需要将 maven 依赖的 c3p0 版本更换为 0.9.2.x 之后的版本就行,推荐 0.9.5.5 最新版。同时配置方式也发生了一些变化:
<!-- Old version setting -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- New version setting -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>