尝试使用hibernate持久保存blob时出现MySQLSyntaxErrorException

时间:2012-11-05 15:05:47

标签: mysql hibernate jpa spring-mvc blob

我正在使用Spring MVC,Hibernate4和MySQL5创建一些简单的网页。我使用的模型之一包含BLOB值(byte [])。当我尝试使用entityManager.persist()保留该模型时 我得到了MySQLSytnaxException。实际上当前配置存在更多问题,例如persist / merge / remove忽略@Transactional注释,但这个是最关键的。

我已尝试使用session.save(object);或替换Blob的byte []。结果仍然相同。我发现的所有工作实例都使用完全不同的方法 - 例如他们使用HibernateSessionManager和HibernateTransactionManager而不是JPA - 我希望找到解决方案,不需要完全改变我如何持久化实体,当我还不确定它会有所帮助时。

你能告诉我在代码/配置/假设方面犯了哪些错误吗?

与Hibernate跟踪一起开始堆栈跟踪:

Hibernate: 
        insert 
        into
            updates
            (changelog, added, developmentVersion, filedata, filedataType, major, minor, nightly, release, package, type, uploader, id) 
        values
            (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
22:53:10,888 TRACE BasicBinder:83 - binding parameter [1] as [VARCHAR] - sdfsd
22:53:10,891 TRACE BasicBinder:71 - binding parameter [2] as [DATE] - <null>
22:53:10,894 TRACE BasicBinder:83 - binding parameter [3] as [BOOLEAN] - false
22:53:10,898 TRACE BasicBinder:83 - binding parameter [4] as [BLOB] - javax.sql.rowset.serial.SerialBlob@298fd36c
22:53:10,924 TRACE BasicBinder:83 - binding parameter [5] as [VARCHAR] - image/png
22:53:10,926 TRACE BasicBinder:83 - binding parameter [6] as [INTEGER] - 1
22:53:10,928 TRACE BasicBinder:83 - binding parameter [7] as [INTEGER] - 0
22:53:10,935 TRACE BasicBinder:83 - binding parameter [8] as [INTEGER] - 0
22:53:10,936 TRACE BasicBinder:83 - binding parameter [9] as [INTEGER] - 0
22:53:10,939 TRACE BasicBinder:83 - binding parameter [10] as [INTEGER] - 36
22:53:10,941 TRACE EnumType:292 - Binding {0} to parameter: {1}
22:53:10,944 TRACE BasicBinder:83 - binding parameter [12] as [INTEGER] - 18
22:53:10,955 TRACE BasicBinder:83 - binding parameter [13] as [INTEGER] - 0
22:53:10,998  WARN SqlExceptionHelper:143 - SQL Error: 1064, SQLState: 42000
22:53:10,999 ERROR SqlExceptionHelper:144 - 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 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1
22:53:11,027  INFO AbstractBatchImpl:195 - HHH000010: On release of batch it still contained JDBC statements
Nov 07, 2012 10:53:11 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [repoApplication] in context with path [/server] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: 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 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: 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 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 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 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1

beans.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    ...
    >

    ...

    <!-- Hibernate configuration -->    

    <!-- Specifies dataSource object managing connections to database -->  
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
        <property name="driverClassName" value="${database.driver}" /> 
        <property name="url" value="${database.url}" /> 
        <property name="username" value="${database.user}" /> 
        <property name="password" value="${database.password}" />
    </bean>

    <!-- Defines SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        ...
        <property name="hibernateProperties">
            <util:properties location="classpath:Hibernate.properties" />
        </property>
    </bean>

    <!-- Defines TransactionManager -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!-- Binds TransactionManager to annotations -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!-- Enables Spring annotations -->
    <context:annotation-config />

    ...

</beans>

Hibernate.properties:

hibernate.database         =MYSQL
hibernate.dialect          =org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql         =true
hibernate.format_sql       =true
hibernate.use_sql_comments =true
hibernate.hbm2ddl.auto     =update

MySQL数据库中的所有表都使用InnoDB引擎。

Update.java(model):

import java.sql.Blob;
import java.sql.Date;
import java.sql.SQLException;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.sql.rowset.serial.SerialBlob;
import javax.validation.constraints.NotNull;

import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

...

@Entity
@Table(name = "updates")
@VersionNumberCorrect
public class Update {
    @Id
    @Column(name = "id", unique = true)
    private int id;

    @NotNull
    @ManyToOne
    @JoinColumn(name = "package")
    private Package thePackage;

    @NotNull
    @ManyToOne
    @JoinColumn(name = "uploader")
    private User uploader;

    @Column(name = "added")
    private Date date;

    @Column(name = "changelog")
    @NotNull
    @NotEmpty
    private String changelog;

    @Column(name = "major")
    private int major;

    @Column(name = "minor")
    private int minor;

    @Column(name = "release")
    private int release;

    @Column(name = "nightly")
    private int nightly;

    @Column(name = "developmentVersion")
    private boolean developmentVersion;

    @Column(name = "type")
    @Enumerated(EnumType.ORDINAL)
    private EUpdateStrategy type;

    @Column(name = "filedata")
    @Lob
    @Type(type = "blob")
    @NotNull
    private Blob filedata;

    @Column(name = "filedataType")
    private String filedataType;

    public Update() {
    }

    ...
}

UpdateServiceImp.java(服务):

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

...

@Service
@Transactional
public class UpdateServiceImp implements UpdateService {
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public void persist(Update update) {
        getSession().persist(update);
    }

    @Override
    public Update merge(Update update) {
        return (Update) getSession().merge(update);
    }

    @Override
    public void remove(Update update) {
        getSession().delete(update);
    }

    ...

    /**
     * Returns new Session instance.
     * 
     * @return new Session
     */
    private Session getSession() {
        return sessionFactory.getCurrentSession();
    }
}

编辑: 我将EntityManagerManager的用法改为Hibernate的SessionFactory - 我试图改变它认为它可能会有所帮助。它没有,但代码有点干净:)。我在Hibernate日志中添加了一些可能有用的信息。我还添加了Hibernate.properties内容,因为这个错误很可能与Hibernate配置有关。

1 个答案:

答案 0 :(得分:6)

感谢一位开发人员的帮助,我发现了什么问题:我使用release作为其中一个属性的名称。我发现release是MySQL中的关键字,当它出现在查询中时,它会使语法无效。

我真的很惊讶地发现Hibernate没有使用带有列',模式'和表名的撇号。我认为以这种方式编写SQL是一种常见做法:

INSERT INTO `mySqlTable` VALUES (null, 'value') ;

INSERT INTO 'dbo'.'msSqlTable' VALUES (null, 'value');

但是Hibernate会这样做:

INSERT INTO mySqlTable VALUES (null, 'value') ;

对于MySQL5,保留字列表很长:http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html

我想我将来必须更加谨慎地选择列名。希望能帮助别人。