Giriş
Bu yazı JPA sağlayıcısı olarak Hibernate kullanıldığında olan şeylerle ilgili. Özet olarak şöyle yapmak lazım. Neden böyle gerektiği ise yazının devamında
Bu yazı JPA sağlayıcısı olarak Hibernate kullanıldığında olan şeylerle ilgili. Özet olarak şöyle yapmak lazım. Neden böyle gerektiği ise yazının devamında
@Entitypublic class Exam {@Lobprivate String description; //Bu işe yaramıyor}@Entitypublic class Exam {@Column(columnDefinition="TEXT")private String text; //Böyle yapmak lazım}
Detaylar
Blob tipini Java kodu içinde saklamak için genelde üye alan olarak iki tip kullanılıyor.
1. byte []
2. String
1. byte []
2. String
Eğer üye alana byte[] ise PostgreSQL BLOB veriyi saklamak için iki farklı sütun sağlar. Bunlar şöyle.
bytea - data stored in table
oid - table holds just identifier to data stored elsewhere
Eğer üye alana String ise PostgreSQL CLOB veriyi saklamak için iki farklı sütun sağlar. Bunlar şöyle.
text
oid
OID Nedir?
Açıklaması şöyle
PostgreSQL provides two distinct ways to store binary data. Binary data can be stored in a table using the data type BYTEA or by using the Large Object feature, which stores the binary data in a separate table in a special format and refers to that table by storing a value of type OID in your table.
OID için bir başka açıklama şöyle.
A column of type Oid is just a reference to the binary contents which are actually stored in the system's pg_largeobject table. In terms of storage, an Oid a 4 byte integer. On the other hand, a column of type bytea is the actual contents.
Problem Nedir?
Burada problem Hibernate'in varsayılan davranış olarak hep OID kullanması ve veriyi PG_LARGEOBJECT tablosunda saklaması
Bu davranışı istemiyoruz çünkü kendi tablomuzdaki satır silinse bile PG_LARGEOBJECT tablosundaki satır silinmez. Açıklaması şöyle.
LOBs are NOT deleted from the database when the rows of your application table (containing the OIDs) get deleted.Bu orphan satırları silmek için VACUUMLO komutu kullanılır.
This also means that space will NOT be reclaimed by the VACUUM process.
In order to get rid of unused LOBs, you have run VACUUMLO on the databases. Vacuumlo will delete all of the unreferenced LOBs from a database.
1. Üye Alan Tipi byte [] İse
Eğer değişken tipi byte [] ise JDBC olarak java.sql.Types.BLOB seçilir. Hibernate şöyle yapar. Yani varsayılan sütun tipi oid tipidir.
public PostgreSQLDialect() {
super();
...
registerColumnType(Types.VARBINARY, "bytea");
/**
* Notice it maps java.sql.Types.BLOB as oid
*/
registerColumnType(Types.BLOB, "oid");
}
bytea Sütun Tipi İle Çalışmak - İstenilen Davranış
bytea binary string anlamına gelir.
Örnek
Eğer sütun tipi bytea ise sütunu yaratmak için şöyle yaparız.
2. Üye Alan Tipi String İsebytea binary string anlamına gelir.
Örnek
Eğer sütun tipi bytea ise sütunu yaratmak için şöyle yaparız.
public class Template {
...
@Lob
@Column(columnDefinition="bytea")
private byte[] data;
}
Örnek
Eğer sütun tipi bytea ise okuyup yazmak için şöyle yaparız.
Eğer sütun tipi bytea ise okuyup yazmak için şöyle yaparız.
@Lob
@Column(name="image")
@Type(type="org.hibernate.type.BinaryType")
private byte[] image;
Elimizde şöyle bir kod olsun
@Entity
@Table(name = "document")
public class Document {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "date_created", nullable = false)
private LocalDateTime dateCreated;
@Column(name = "doc_txt")
private String docText;
//Getters and setters omitted for brevity
}
Burada veri tabanındaki sütunun varsayılan uzunluğu 255. Açıklaması şöyle
In Java, the string datatype can hold about 2Gb of text data, but the table column size will be limited to 255 characters by default for the model above.
Dolayısıyla eğer uzun bir String tipi kaydederken org.postgresql.util.PSQLException: ERROR: value too long for type character varying(255) hatası alabiliriz.
2.1 @Lob Olarak İşaretlemek - İstemiyoruz
Biz de sütunumuzu @Lob ile işaretlemeye karar veririz. Bu durumda üye alan için ise JDBC tiplerinden java.sql.Types.CLOB seçilir. PostgreSQL CLOB sütunu olarak text tipini kullanır. Ancak Hibernate String'i de aynı oid gibi başka bir alanda saklar!
Örnek
Hibernate tarafından üretilen SQL şöyledir
CREATE TABLE document (
id INT8 GENERATED BY DEFAULT AS IDENTTITY,
date_created TIMESTAMPT NOT NULL,
doc_txt OID,
PRIMARY KEY (id)
);
Eğer tabloya bakarsak veri şöyledir
SELECT * FROM document
id date_created doc_txt
1 2020-01-01 10:10:00 76388
Yani veri başka tabloda. Veriyi görmek için şöyle yaparız
SELECT * FROM pg_largeobject WHERE loid=76338
Örnek
Elimizde şöyle bir kod olsun.
String'i tablo içinde saklamak için şöyle yaparız
@Column(name = "xml")
@Lob
private String xml;
Bu tabloya bakarsak xml sütunu text tipindendir.Column | Type | Modifiers
----------------+-----------------------------+-----------
xml | text |
xml sütunundaki veriye bakarsak oid değer görürüz.# select * from tablename
xml
+------------
242781
(1 row)
2.2 Text Sütun Tipi İle Çalışmak - İstenilen Davranış
Örnek - Kolay yolString'i tablo içinde saklamak için şöyle yaparız
@Column(columnDefinition="text")
private String column;
Açıklaması şöyle. Yani 1 GB civarında metin saklanabilir.
.. , the longest possible character string that can be stored is about 1 GB...
It is smaller than 4Gb, allowed by LOB storage, but still long enough for most use cases.
Örnek - Hibernate 6
Şöyle yaparız
@Column(name = "doc_txt", length = Length.LOB_DEFAULT)
private String docText;
Açıklaması şöyle. Yani sütun TEXT tipinden olmuyor
In Hibernate 6, the org.hibernate.type.TextType class was removed. To define a column to store a long text, we can define the attribute in the following way:This will give us the following column definition in the database: doc_txt varchar(1048576). It is not the TEXT datatype, but it can still store about 1Gb of text in the table. It is the largest possible character string in PostgreSQL.
Yani sütun TEXT tipinden olsun istersek şöyle yaparız
@JdbcTypeCode(SqlTypes.LONG32VARCHAR)
@Column(name = "doc_txt")
private String docText;
Örnek - Hibernate 5 Anotasyonu
The Hibernate @Type value that maps to PG's Text data type is org.hibernate.type.TextType. This is what you should use.String'i tablo içinde saklamak için bir tane daha Hibernate anotasyonu ekleriz. Şöyle yaparız.
@Type(type="org.hibernate.type.TextType")
Örnek
Şöyle yaparız
@Type(type = "org.hibernate.type.TextType")
@Column(name = "doc_txt")
private String docText;
Hiç yorum yok:
Yorum Gönder