正如标题所示,我正在为我的数据访问层使用Spring Boot和Hibernate构建一个Web应用程序,并且开发是在InteliJ IDEA 14.1.2上完成的。
我的知识
这是我第一次使用Spring Boot,Hibernate和InteliJ。我已经构建了一些小应用程序来测试Spring Boot和Hibernate,但是这些和我现在正在构建的应用程序之间的复杂性差异要大一些。
环境
关于我的环境,如果重要,我在运行Redis 3.0.1服务器的VirtualBox 4.3.26 VM上运行Windows 7 SP1 64位,MySQL服务器5.6.17,InteliJ 14.1.2和Ubuntu Server 14.04。 / p>
目的
此时使用上述技术的目的是将不同实体存储和检索到MySQL数据库(Redis仅用于会话外部化和应用程序实例之间的共享)。换句话说,我正在构建我的数据访问层。
数据库
我的完整数据库架构可以在这里找到:
https://dl.dropboxusercontent.com/u/49544122/so/DB.pdf
来源
My Spring Boot应用程序如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import se.domain.cvs.abstraction.dataaccess.AccountRepository;
import se.domain.cvs.domain.AccountEntity;
@SpringBootApplication
@EnableRedisHttpSession
public class Application implements CommandLineRunner {
@Autowired
AccountRepository repository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... strings) throws Exception {
System.out.println("=======================================================");
AccountEntity account = repository.findByEmail("r.franklin@companya.se");
System.out.println("My name is " + account.getFirstName() + " " + account.getLastName());
System.out.println("=======================================================");
}
}
我正在使用CommandLineRunner接口来测试裸数据访问层而不引入REST端点。
我的配置如下YAML格式:
...
# MySQL Database Configuration
spring.datasource:
url: jdbc:mysql://localhost:3306/cvs
username: cvs
password: cvs
driverClassName: com.mysql.jdbc.Driver
spring.jpa:
database: MYSQL
show-sql: true
hibernate.ddl-auto: validate
hibernate.naming-strategy: org.hibernate.cfg.DefaultNamingStrategy
properties.hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
...
使用InteliJ自动生成JPA实体,这就是问题开始的地方。让我们以下面的OrderEntity为例(为了简洁起见,我省略了一些代码):
...
@Entity
@Table(name = "order", schema = "", catalog = "cvs")
public class OrderEntity {
...
private int invoiceId;
...
private InvoiceEntity invoiceByInvoiceId;
...
@Basic
@Column(name = "InvoiceID", nullable = false, insertable = false, updatable = false)
public int getInvoiceId() {
return invoiceId;
}
public void setInvoiceId(int invoiceId) {
this.invoiceId = invoiceId;
}
...
@ManyToOne
@JoinColumn(name = "InvoiceID", referencedColumnName = "InvoiceID", nullable = false)
public InvoiceEntity getInvoiceByInvoiceId() {
return invoiceByInvoiceId;
}
public void setInvoiceByInvoiceId(InvoiceEntity invoiceByInvoiceId) {
this.invoiceByInvoiceId = invoiceByInvoiceId;
}
...
}
尝试运行Spring Boot应用程序时,出现以下错误:
org.hibernate.MappingException: Repeated column in mapping for entity: OrderEntity column: invoiceId (should be mapped with insert="false" update="false")
在做了一些研究之后,我想问题是invoiceID现在有两种设置方式,一种是通过setInvoiceID()
setter,一种是通过InvoiceEntity
对象本身设置OrderEntity涉及,可能导致不一致的状态。正如另一位用户所说,
当创建/更新相关实体的责任不在当前实体中时,您会这样做。
请在此处查看相关信息:Please explain about: insertable=false, updatable=false
将相应字段(insertable
和updateable
)的建议值设置为false可修复错误。
我的问题是为什么这会产生错误的方式?我的更改修复了错误,但我想确保我的SQL中没有错误导致InteliJ以错误的方式生成错误。完整的SQL脚本可以在http://pastebin.com/aDguqR1N找到。
此外,在生成实体时,InteliJ需要一个Hibernate配置文件,我猜Spring Boot自己在其他地方生成(或使用基于Java的配置)。无论我把它留在那里还是删除它,它似乎都不会影响应用程序。我猜SB读取属性的顺序会覆盖它。我可以删除它吗?
非常感谢你的时间和提前帮助,对不起这篇长篇文章感到抱歉! :)
答案 0 :(得分:0)
我的建议是让Spring / Hibernate为你生成db模式(包括外键和约束在内的所有内容都可以由Spring生成。
对我来说,下面的方法是有效的:
父实体中的(在我的情况下是TblUser):
@OneToMany(targetEntity=TblTracks.class,fetch=FetchType.EAGER,cascade=CascadeType.ALL,mappedBy="tbluser")
private List<TblTracks> tbltracks= new ArrayList<TblTracks>();
其中mappedBy指向子实体的Tbluser实体(私有TblUser tbluser)
并且在子实体(在我的情况下是TblTracks)中
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="idTblUser",nullable=false)
private TblUser tbluser;