Trong trường hợp tên column của table trong database mà các bạn đang làm việc không giống với tên của entity mà các bạn đang định nghĩa, các bạn có thể sử dụng annotation @Column để thay đổi tên này. Ở đây, còn một số chức năng khác mà annotation này hỗ trợ cho chúng ta. Hãy cùng nhau tìm hiểu về nó trong bài viết này các bạn nhé!
Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:
Maven dependencies:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.12.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.2.12.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <scope>provided</scope> </dependency> |
Trong bài viết này, mình sẽ dùng database là MySQL với một table tên là clazz, được định nghĩa với cấu trúc như sau:
1 2 3 4 5 |
CREATE TABLE `clazz` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
Entity của table này được định nghĩa ban đầu như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package com.huongdanjava.jpacolumn; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import lombok.Getter; import lombok.Setter; @Entity @Table @Getter @Setter public class Clazz { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; } |
Nội dung tập tin cấu hình của JPA:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence_2_1.xsd"> <persistence-unit name="jpaexample" transaction-type="RESOURCE_LOCAL"> <class>com.huongdanjava.jpacolumn.Clazz</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa_example" /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="123456" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.use_sql_comments" value="true" /> <property name="hibernate.id.new_generator_mappings" value="false" /> </properties> </persistence-unit> </persistence> |
Application class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.huongdanjava.jpacolumn; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class Application { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaexample"); EntityManager em = emf.createEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin(); Clazz clazz = new Clazz(); clazz.setName("Class A"); em.persist(clazz); transaction.commit(); } } |
OK, vậy là mọi thứ chuẩn bị đã xong, giờ chúng ta sẽ đi vào chủ đề chính của bài viết này nhé các bạn!
Trong ví dụ của mình, bởi vì các thuộc tính của entity Clazz đều giống với tên của các column trong bảng clazz nên mình không cần sử dụng @Column annotation cũng được:
1 |
private String name; |
Khi đó, các bạn có thể insert record mới vào table clazz mà không có vấn đề gì cả.
Nếu thuộc tính name của entity Clazz là một giá trị khác, ví dụ mình đổi thành className, thì chúng ta cần phải khai báo để sử dụng annotation @Column như sau:
1 2 |
@Column(name = "name") private String className; |
Kết quả cũng vậy:
Trong annotation @Column, ngoài thuộc tính name ra, chúng ta còn có thể khai báo các thuộc tính khác như sau (đa số các thuộc tính này dùng để định nghĩa cấu trúc của column, cần thiết khi chúng ta sử dụng JPA Tool để generate table từ entity) :
columnDefinition
Thuộc tính này cho phép các bạn sử dụng ngôn ngữ định dạng dữ liệu (DDL) để định nghĩa cấu trúc của một column. Sau đó, chúng ta có thể generate table từ entity sử dụng JPA Tool với định nghĩa này. Sử dụng thuộc tính này, các bạn có thể định nghĩa độ dài giá trị của cột (length), độ chính xác (precision) dành cho column với kiểu giá trị DECIMAL, khả năng mở rộng (scale) cũng dành cho column với kiểu giá trị DECIMAL, có được phép null hay không (nullable), có tính duy nhất không (unique).
Ví dụ, các bạn có thể định nghĩa column name sử dụng annotation @Column với thuộc tính columnDefinition như sau:
1 2 |
@Column(name = "name", columnDefinition = "VARCHAR(4) NOT NULL") private String className; |
Khi sử dụng JPA Tool để generate table thì column này sẽ có cấu trúc như sau:
1 |
`name` VARCHAR(4) NOT NULL |
insertable
Thuộc tính này được sử dụng để cho phép sử dụng column này trong câu lệnh INSERT hay không? Mặc định giá trị của thuộc tính này là true, nếu các bạn định nghĩa thuộc tính này là false như sau:
1 2 |
@Column(name = "name", insertable = false) private String className; |
thì khi chạy lại ví dụ, các bạn sẽ thấy lỗi như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute statement at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:789) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:767) at com.huongdanjava.jpacolumn.Application.main(Application.java:19) Caused by: org.hibernate.exception.GenericJDBCException: could not execute statement at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178) at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57) at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2919) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3490) at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81) at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:626) at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:280) at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:261) at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:306) at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:318) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113) at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:782) ... 2 more Caused by: java.sql.SQLException: Field 'name' doesn't have a default value at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:545) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:513) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:115) at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:1983) at com.mysql.cj.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1826) at com.mysql.cj.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2034) at com.mysql.cj.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:1970) at com.mysql.cj.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5001) at com.mysql.cj.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1955) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175) ... 20 more |
length
Thuộc tính này định nghĩa độ dài giá trị của column. Nó sẽ bị override nếu các bạn đã định nghĩa độ dài của column trong thuộc tính columnDefinition.
nullable
Thuộc tính này định nghĩa có cho phép column này null hay không. Nó cũng sẽ bị override nếu các bạn đã định nghĩa trong thuộc tính columnDefinition.
precision
Thuộc tính này định nghĩa độ chính xác giá trị của column với kiểu giá trị DECIMAL. Nó cũng sẽ bị override nếu các bạn đã định nghĩa trong thuộc tính columnDefinition.
scale
Thuộc tính này định nghĩa khả năng mở rộng của column với kiểu giá trị DECIMAL. Nó cũng sẽ bị override nếu các bạn đã định nghĩa trong thuộc tính columnDefinition.
Một ví dụ với thuộc tính precision và scale là:
1 |
salary DECIMAL(5,2); |
trong đó: 5 là precision còn 2 là scale. Giá trị của cột này có dạng như sau: 123.45, có thể làm tròn phần thập phân 2 chữ số.
table
Định nghĩa table mà column này thuộc về.
unique
Định nghĩa tính duy nhất của giá trị mà column này chứa. Có thể dùng để định nghĩa cho primary key column đấy các bạn!
updatable
Giống như thuộc tính insertable, thuộc tính này định nghĩa có cho phép sử dụng column này trong câu lệnh UPDATE hay không? Mặc định giá trị của thuộc tính này là true nha các bạn!