@@ -5,6 +5,7 @@ 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
910import org.hibernate.hikaricp.internal.HikariCPConnectionProvider
1011import org.hibernate.jpa.HibernatePersistenceConfiguration
@@ -45,17 +46,16 @@ fun main() {
4546}
4647
4748private fun SessionFactory.insertSampleData () {
48- withTransaction { session ->
49+ inTransaction { session ->
4950 // a few artists and albums (minimal, not used further; just demo schema)
5051 val artist1 = ArtistsEntity (name = " AC/DC" )
5152 val artist2 = ArtistsEntity (name = " Queen" )
5253 session.persist(artist1)
5354 session.persist(artist2)
54- session.flush()
5555
56- session.persist(AlbumsEntity (title = " High Voltage" , artistId = artist1.artistId !! ))
57- session.persist(AlbumsEntity (title = " Back in Black" , artistId = artist1.artistId !! ))
58- 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))
5959 // customers we'll analyze using DataFrame
6060 session.persist(
6161 CustomersEntity (
@@ -91,15 +91,15 @@ private fun SessionFactory.loadCustomersAsDataFrame(): DataFrame<DfCustomers> =
9191 val root: Root <CustomersEntity > = criteriaQuery.from(CustomersEntity ::class .java)
9292 criteriaQuery.select(root)
9393
94- session.createQuery (criteriaQuery)
94+ session.createSelectionQuery (criteriaQuery)
9595 .resultList
9696 .map { c ->
9797 DfCustomers (
9898 address = c.address,
9999 city = c.city,
100100 company = c.company,
101101 country = c.country,
102- customerId = c.customerId ? : - 1 ,
102+ customerId = c.customerId ? : error( " Loaded customer must have a generated id " ) ,
103103 email = c.email,
104104 fax = c.fax,
105105 firstName = c.firstName,
@@ -120,7 +120,7 @@ private fun SessionFactory.loadCustomersAsDataFrame(): DataFrame<DfCustomers> =
120120 }
121121
122122/* * DTO used for aggregation projection. */
123- private data class CountryCountDto (val country : String , val customerCount : Long )
123+ private data class CountryCountDto (val country : String? , val customerCount : Long )
124124
125125/* *
126126 * **Hibernate + Criteria API:**
@@ -134,9 +134,8 @@ private fun SessionFactory.countCustomersPerCountryWithHibernate() {
134134 val cb = session.criteriaBuilder
135135 val cq: CriteriaQuery <CountryCountDto > = cb.createQuery(CountryCountDto ::class .java)
136136 val root: Root <CustomersEntity > = cq.from(CustomersEntity ::class .java)
137-
138- val countryPath = root.get<String >(" country" )
139- val idPath = root.get<Long >(" customerId" )
137+ val countryPath = root.get<String ?>(" country" )
138+ val idPath = root.get<Int ?>(" customerId" )
140139
141140 val countExpr = cb.count(idPath)
142141
@@ -150,7 +149,7 @@ private fun SessionFactory.countCustomersPerCountryWithHibernate() {
150149 cq.groupBy(countryPath)
151150 cq.orderBy(cb.desc(countExpr))
152151
153- val results = session.createQuery (cq).resultList
152+ val results = session.createSelectionQuery (cq).resultList
154153 results.forEach { dto ->
155154 println (" ${dto.country} : ${dto.customerCount} customers" )
156155 }
@@ -177,22 +176,18 @@ private fun DataFrame<DfCustomers>.analyzeAndPrintResults() {
177176 .print (columnTypes = true , borders = true )
178177}
179178
180- private fun SessionFactory.replaceCustomersFromDataFrame (df : DataFrame <DfCustomers >) {
181- withTransaction { session ->
179+ private fun SessionFactory.replaceCustomersFromDataFrame (df : DataFrame <DfCustomers >) =
180+ inTransaction { session ->
182181 val criteriaBuilder: CriteriaBuilder = session.criteriaBuilder
183182 val criteriaDelete: CriteriaDelete <CustomersEntity > =
184183 criteriaBuilder.createCriteriaDelete(CustomersEntity ::class .java)
185184 criteriaDelete.from(CustomersEntity ::class .java)
186-
187185 session.createMutationQuery(criteriaDelete).executeUpdate()
188- }
189186
190- withTransaction { session ->
191187 df.asSequence().forEach { row ->
192188 session.persist(row.toCustomersEntity())
193189 }
194190 }
195- }
196191
197192private fun DataRow<DfCustomers>.toCustomersEntity (): CustomersEntity =
198193 CustomersEntity (
@@ -211,37 +206,13 @@ private fun DataRow<DfCustomers>.toCustomersEntity(): CustomersEntity =
211206 supportRepId = this .supportRepId,
212207 )
213208
214- private inline fun <T > SessionFactory.withSession (block : (session: org.hibernate.Session ) -> T ): T =
215- openSession().use(block)
216-
217- private inline fun SessionFactory.withTransaction (block : (session: org.hibernate.Session ) -> Unit ) {
218- withSession { session ->
219- session.beginTransaction()
220- try {
221- block(session)
222- session.transaction.commit()
223- } catch (e: Exception ) {
224- session.transaction.rollback()
225- throw e
226- }
227- }
228- }
229-
230209/* * Read-only transaction helper for SELECT queries to minimize overhead. */
231- private inline fun <T > SessionFactory.withReadOnlyTransaction (block : (session: org.hibernate.Session ) -> T ): T =
232- withSession { session ->
233- session.beginTransaction()
210+ private inline fun <T > SessionFactory.withReadOnlyTransaction (crossinline block : (session: Session ) -> T ): T =
211+ fromTransaction { session ->
234212 // Minimize overhead for read operations
235213 session.isDefaultReadOnly = true
236214 session.hibernateFlushMode = FlushMode .MANUAL
237- try {
238- val result = block(session)
239- session.transaction.commit()
240- result
241- } catch (e: Exception ) {
242- session.transaction.rollback()
243- throw e
244- }
215+ block(session)
245216 }
246217
247218private fun buildSessionFactory (): SessionFactory =
0 commit comments