@@ -5,8 +5,11 @@ import jakarta.persistence.criteria.CriteriaDelete
55import jakarta.persistence.criteria.CriteriaQuery
66import jakarta.persistence.criteria.Root
77import org.hibernate.FlushMode
8+ import org.hibernate.Session
89import org.hibernate.SessionFactory
9- import org.hibernate.cfg.Configuration
10+ import org.hibernate.hikaricp.internal.HikariCPConnectionProvider
11+ import org.hibernate.jpa.HibernatePersistenceConfiguration
12+ import org.hibernate.tool.schema.Action
1013import org.jetbrains.kotlinx.dataframe.DataFrame
1114import org.jetbrains.kotlinx.dataframe.DataRow
1215import org.jetbrains.kotlinx.dataframe.api.asSequence
@@ -43,17 +46,16 @@ fun main() {
4346}
4447
4548private fun SessionFactory.insertSampleData () {
46- withTransaction { session ->
49+ inTransaction { session ->
4750 // a few artists and albums (minimal, not used further; just demo schema)
4851 val artist1 = ArtistsEntity (name = " AC/DC" )
4952 val artist2 = ArtistsEntity (name = " Queen" )
5053 session.persist(artist1)
5154 session.persist(artist2)
52- session.flush()
5355
54- session.persist(AlbumsEntity (title = " High Voltage" , artistId = artist1.artistId !! ))
55- session.persist(AlbumsEntity (title = " Back in Black" , artistId = artist1.artistId !! ))
56- session.persist(AlbumsEntity (title = " A Night at the Opera" , artistId = artist2.artistId !! ))
56+ session.persist(AlbumsEntity (title = " High Voltage" , artist = artist1))
57+ session.persist(AlbumsEntity (title = " Back in Black" , artist = artist1))
58+ session.persist(AlbumsEntity (title = " A Night at the Opera" , artist = artist2))
5759 // customers we'll analyze using DataFrame
5860 session.persist(
5961 CustomersEntity (
@@ -89,15 +91,15 @@ private fun SessionFactory.loadCustomersAsDataFrame(): DataFrame<DfCustomers> =
8991 val root: Root <CustomersEntity > = criteriaQuery.from(CustomersEntity ::class .java)
9092 criteriaQuery.select(root)
9193
92- session.createQuery (criteriaQuery)
94+ session.createSelectionQuery (criteriaQuery)
9395 .resultList
9496 .map { c ->
9597 DfCustomers (
9698 address = c.address,
9799 city = c.city,
98100 company = c.company,
99101 country = c.country,
100- customerId = c.customerId ? : - 1 ,
102+ customerId = c.customerId ? : error( " Loaded customer must have a generated id " ) ,
101103 email = c.email,
102104 fax = c.fax,
103105 firstName = c.firstName,
@@ -118,7 +120,7 @@ private fun SessionFactory.loadCustomersAsDataFrame(): DataFrame<DfCustomers> =
118120 }
119121
120122/* * DTO used for aggregation projection. */
121- private data class CountryCountDto (val country : String , val customerCount : Long )
123+ private data class CountryCountDto (val country : String? , val customerCount : Long )
122124
123125/* *
124126 * **Hibernate + Criteria API:**
@@ -132,9 +134,8 @@ private fun SessionFactory.countCustomersPerCountryWithHibernate() {
132134 val cb = session.criteriaBuilder
133135 val cq: CriteriaQuery <CountryCountDto > = cb.createQuery(CountryCountDto ::class .java)
134136 val root: Root <CustomersEntity > = cq.from(CustomersEntity ::class .java)
135-
136- val countryPath = root.get<String >(" country" )
137- val idPath = root.get<Long >(" customerId" )
137+ val countryPath = root.get<String ?>(" country" )
138+ val idPath = root.get<Int ?>(" customerId" )
138139
139140 val countExpr = cb.count(idPath)
140141
@@ -148,7 +149,7 @@ private fun SessionFactory.countCustomersPerCountryWithHibernate() {
148149 cq.groupBy(countryPath)
149150 cq.orderBy(cb.desc(countExpr))
150151
151- val results = session.createQuery (cq).resultList
152+ val results = session.createSelectionQuery (cq).resultList
152153 results.forEach { dto ->
153154 println (" ${dto.country} : ${dto.customerCount} customers" )
154155 }
@@ -175,22 +176,18 @@ private fun DataFrame<DfCustomers>.analyzeAndPrintResults() {
175176 .print (columnTypes = true , borders = true )
176177}
177178
178- private fun SessionFactory.replaceCustomersFromDataFrame (df : DataFrame <DfCustomers >) {
179- withTransaction { session ->
179+ private fun SessionFactory.replaceCustomersFromDataFrame (df : DataFrame <DfCustomers >) =
180+ inTransaction { session ->
180181 val criteriaBuilder: CriteriaBuilder = session.criteriaBuilder
181182 val criteriaDelete: CriteriaDelete <CustomersEntity > =
182183 criteriaBuilder.createCriteriaDelete(CustomersEntity ::class .java)
183184 criteriaDelete.from(CustomersEntity ::class .java)
184-
185185 session.createMutationQuery(criteriaDelete).executeUpdate()
186- }
187186
188- withTransaction { session ->
189187 df.asSequence().forEach { row ->
190188 session.persist(row.toCustomersEntity())
191189 }
192190 }
193- }
194191
195192private fun DataRow<DfCustomers>.toCustomersEntity (): CustomersEntity =
196193 CustomersEntity (
@@ -209,40 +206,21 @@ private fun DataRow<DfCustomers>.toCustomersEntity(): CustomersEntity =
209206 supportRepId = this .supportRepId,
210207 )
211208
212- private inline fun <T > SessionFactory.withSession (block : (session: org.hibernate.Session ) -> T ): T =
213- openSession().use(block)
214-
215- private inline fun SessionFactory.withTransaction (block : (session: org.hibernate.Session ) -> Unit ) {
216- withSession { session ->
217- session.beginTransaction()
218- try {
219- block(session)
220- session.transaction.commit()
221- } catch (e: Exception ) {
222- session.transaction.rollback()
223- throw e
224- }
225- }
226- }
227-
228209/* * Read-only transaction helper for SELECT queries to minimize overhead. */
229- private inline fun <T > SessionFactory.withReadOnlyTransaction (block : (session: org.hibernate.Session ) -> T ): T =
230- withSession { session ->
231- session.beginTransaction()
210+ private inline fun <T > SessionFactory.withReadOnlyTransaction (crossinline block : (session: Session ) -> T ): T =
211+ fromTransaction { session ->
232212 // Minimize overhead for read operations
233213 session.isDefaultReadOnly = true
234214 session.hibernateFlushMode = FlushMode .MANUAL
235- try {
236- val result = block(session)
237- session.transaction.commit()
238- result
239- } catch (e: Exception ) {
240- session.transaction.rollback()
241- throw e
242- }
215+ block(session)
243216 }
244217
245- private fun buildSessionFactory (): SessionFactory {
246- // Load configuration from resources/hibernate/hibernate.cfg.xml
247- return Configuration ().configure(" hibernate/hibernate.cfg.xml" ).buildSessionFactory()
248- }
218+ private fun buildSessionFactory (): SessionFactory = HibernatePersistenceConfiguration (" hibernate-example" )
219+ .managedClasses(CustomersEntity ::class .java, ArtistsEntity ::class .java, AlbumsEntity ::class .java)
220+ .jdbcUrl(" jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" )
221+ .jdbcCredentials(" sa" , " " )
222+ .schemaToolingAction(Action .CREATE_DROP )
223+ .showSql(true , true , true )
224+ .property(" hibernate.connection.provider_class" , HikariCPConnectionProvider ::class .java)
225+ .property(" hibernate.hikari.maximumPoolSize" , 5 )
226+ .createEntityManagerFactory()
0 commit comments