JavaPersistenceWithHibernate第二版笔记Getting started with ORM-001用JPA和Hibernate实现HellowWorld(JTA、Bitronix)
一、结构
二、model层
1.
1 package org.jpwh.model.helloworld; 2 3 import javax.persistence.Entity; 4 import javax.persistence.GeneratedValue; 5 import javax.persistence.GenerationType; 6 import javax.persistence.Id; 7 8 /* 9 Every persistent entity class must have at least the <code>@Entity</code> annotation. 10 Hibernate maps this class to a table called <code>MESSAGE</code>. 11 */ 12 @Entity 13 public class Message { 14 15 /* 16 Every persistent entity class must have an identifier 17 attribute annotated with <code>@Id</code>. Hibernate maps 18 this attribute to a column named <code>ID</code>. 19 */ 20 @Id 21 /* 22 Someone must generate identifier values; this annotation enables 23 automatic generation of IDs. 24 */ 25 @GeneratedValue//(strategy=GenerationType.TABLE) 26 private Long id; 27 28 /* 29 You usually implement regular attributes of a persistent class with private 30 or protected fields, and public getter/setter method pairs. Hibernate maps 31 this attribute to a column called <code>TEXT</code>. 32 */ 33 private String text; 34 35 public String getText() { 36 return text; 37 } 38 39 public void setText(String text) { 40 this.text = text; 41 } 42 }
三、配置文件
1.persistence.xml(这个文件似乎不起作用)
1 <persistence 2 version="2.1" 3 xmlns="http://xmlns.jcp.org/xml/ns/persistence" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 6 http://xmlns.jcp.org/xml/ns/persistence_2_1.xsd"> 7 8 <!-- 9 The <code>persistence.xml</code> file configures at least one persistence unit; 10 each unit must have a unique name. 11 --> 12 <persistence-unit name="HelloWorldPU"> 13 14 <!-- 15 Each persistence unit must have a database connection. Here you delegate to 16 an existing <code>java.sql.DataSource</code>. Hibernate will find the data source 17 by name with a JNDI lookup on startup. 18 --> 19 <!-- delegate database connection handling to a 20 Java Transaction API ( JTA ) provider, the open source Bitronix project. --> 21 <jta-data-source>myDS2</jta-data-source> 22 23 <!-- 24 A persistent unit has persistent (mapped) classes, you list them here. 25 --> 26 <class>org.jpwh.model.helloworld.Message</class> 27 28 <!-- 29 Hibernate can scan your classpath for mapped classes and add them automatically 30 to your persistence unit. This setting disables that feature. 31 --> 32 <exclude-unlisted-classes>true</exclude-unlisted-classes> 33 34 <!-- 35 Standard or vendor-specific options can be set as properties on a persistence unit. 36 Any standard properties have the <code>javax.persistence</code> name prefix, Hibernate's 37 settings use <code>hibernate</code> 38 --> 39 <properties> 40 41 <!-- 42 The JPA engine should drop and re-create the SQL schema in the database 43 automatically when it boots. This is ideal for automated testing, when 44 you want to work with a clean database for every test run. 45 --> 46 <property 47 name="javax.persistence.schema-generation.database.action" 48 value="update"/> 49 <!-- drop-and-create --> 50 51 <!-- 52 When printing SQL in logs, let Hibernate format the SQL nicely and generate 53 comments into the SQL string so we know why Hibernate executed the SQL statement. 54 --> 55 <property name="hibernate.format_sql" value="true"/> 56 <property name="hibernate.use_sql_comments" value="true"/> 57 58 <!-- Disable Hibernate scanning completely, we also don't want any hbm.xml files 59 discovered and added automatically. --> 60 <property name="hibernate.archive.autodetection" value="none"/> 61 62 </properties> 63 </persistence-unit> 64 65 <persistence-unit name="SimplePU"> 66 <jta-data-source>myDS</jta-data-source> 67 <mapping-file>simple/Queries.xml</mapping-file> 68 <class>org.jpwh.model</class> 69 <class>org.jpwh.model.simple.Item</class> 70 <class>org.jpwh.model.simple.User</class> 71 <class>org.jpwh.model.simple.Bid</class> 72 <class>org.jpwh.model.simple.Address</class> 73 <class>org.jpwh.model.simple.Category</class> 74 <exclude-unlisted-classes>true</exclude-unlisted-classes> 75 <properties> 76 <!-- When remove(entity) is called, reset the identifier value of entity. 77 so it's considered transient after removal --> 78 <property name="hibernate.use_identifier_rollback" value="true"/> 79 80 <!-- Enable this to try a custom table naming strategy 81 <property name="hibernate.physical_naming_strategy" 82 value="org.jpwh.shared.CENamingStrategy"/> 83 --> 84 85 </properties> 86 </persistence-unit> 87 88 <persistence-unit name="SimpleXMLCompletePU"> 89 <jta-data-source>myDS</jta-data-source> 90 91 <mapping-file>simple/Mappings.xml</mapping-file> 92 <mapping-file>simple/Queries.xml</mapping-file> 93 <properties> 94 <!-- Ignore hbm.xml files and annotated classes --> 95 <property name="hibernate.archive.autodetection" 96 value="none"/> 97 </properties> 98 </persistence-unit> 99 100 <persistence-unit name="SimpleXMLOverridePU"> 101 <jta-data-source>myDS</jta-data-source> 102 <mapping-file>simple/Queries.xml</mapping-file> 103 <mapping-file>simple/MappingsOverride.xml</mapping-file> 104 <class>org.jpwh.model</class> 105 <class>org.jpwh.model.simple.Item</class> 106 <class>org.jpwh.model.simple.User</class> 107 <class>org.jpwh.model.simple.Bid</class> 108 <class>org.jpwh.model.simple.Address</class> 109 <class>org.jpwh.model.simple.Category</class> 110 <exclude-unlisted-classes>true</exclude-unlisted-classes> 111 </persistence-unit> 112 113 <persistence-unit name="SimpleXMLHibernatePU"> 114 <jta-data-source>myDS</jta-data-source> 115 <properties> 116 <!-- Only detect hbm.xml files, ignore annotations 117 <property name="hibernate.archive.autodetection" 118 value="hbm"/> 119 --> 120 <!-- But in our environment, we have many conflicting hbm.xml 121 files, so we need to pick which ones we need in each unit test. --> 122 <property name="hibernate.archive.autodetection" 123 value="none"/> 124 </properties> 125 </persistence-unit> 126 127 <persistence-unit name="ConverterPU"> 128 <jta-data-source>myDS</jta-data-source> 129 <class>org.jpwh.model</class> 130 <class>org.jpwh.model.advanced.converter.Item</class> 131 <class>org.jpwh.model.advanced.converter.User</class> 132 <!-- 133 If automatic discovery/scanning is disabled, you have to 134 add your @Converter classes here. In fact, to be compatible 135 with Java SE, converter classes should always be listed here. 136 --> 137 <class>org.jpwh.converter.MonetaryAmountConverter</class> 138 <class>org.jpwh.converter.ZipcodeConverter</class> 139 <exclude-unlisted-classes>true</exclude-unlisted-classes> 140 </persistence-unit> 141 142 <persistence-unit name="UserTypePU"> 143 <jta-data-source>myDS</jta-data-source> 144 <class>org.jpwh.model</class> 145 <!-- For @TypeDefs in package-info.java --> 146 <class>org.jpwh.converter</class> 147 <class>org.jpwh.model.advanced.usertype.Item</class> 148 <exclude-unlisted-classes>true</exclude-unlisted-classes> 149 </persistence-unit> 150 151 <persistence-unit name="MappedSuperclassPU"> 152 <jta-data-source>myDS</jta-data-source> 153 <class>org.jpwh.model</class> 154 <class>org.jpwh.model.inheritance.mappedsuperclass.BillingDetails</class> 155 <class>org.jpwh.model.inheritance.mappedsuperclass.CreditCard</class> 156 <class>org.jpwh.model.inheritance.mappedsuperclass.BankAccount</class> 157 <exclude-unlisted-classes>true</exclude-unlisted-classes> 158 </persistence-unit> 159 160 <persistence-unit name="TablePerClassPU"> 161 <jta-data-source>myDS</jta-data-source> 162 <class>org.jpwh.model</class> 163 <class>org.jpwh.model.inheritance.tableperclass.BillingDetails</class> 164 <class>org.jpwh.model.inheritance.tableperclass.CreditCard</class> 165 <class>org.jpwh.model.inheritance.tableperclass.BankAccount</class> 166 <exclude-unlisted-classes>true</exclude-unlisted-classes> 167 </persistence-unit> 168 169 <persistence-unit name="SingleTablePU"> 170 <jta-data-source>myDS</jta-data-source> 171 <class>org.jpwh.model</class> 172 <class>org.jpwh.model.inheritance.singletable.BillingDetails</class> 173 <class>org.jpwh.model.inheritance.singletable.CreditCard</class> 174 <class>org.jpwh.model.inheritance.singletable.BankAccount</class> 175 <exclude-unlisted-classes>true</exclude-unlisted-classes> 176 </persistence-unit> 177 178 <persistence-unit name="JoinedPU"> 179 <jta-data-source>myDS</jta-data-source> 180 <class>org.jpwh.model</class> 181 <class>org.jpwh.model.inheritance.joined.BillingDetails</class> 182 <class>org.jpwh.model.inheritance.joined.CreditCard</class> 183 <class>org.jpwh.model.inheritance.joined.BankAccount</class> 184 <exclude-unlisted-classes>true</exclude-unlisted-classes> 185 </persistence-unit> 186 187 <persistence-unit name="MixedPU"> 188 <jta-data-source>myDS</jta-data-source> 189 <class>org.jpwh.model</class> 190 <class>org.jpwh.model.inheritance.mixed.BillingDetails</class> 191 <class>org.jpwh.model.inheritance.mixed.CreditCard</class> 192 <class>org.jpwh.model.inheritance.mixed.BankAccount</class> 193 <exclude-unlisted-classes>true</exclude-unlisted-classes> 194 </persistence-unit> 195 196 <persistence-unit name="MixedFetchSelectPU"> 197 <jta-data-source>myDS</jta-data-source> 198 <class>org.jpwh.model</class> 199 <exclude-unlisted-classes>true</exclude-unlisted-classes> 200 </persistence-unit> 201 202 <persistence-unit name="InheritanceEmbeddablePU"> 203 <jta-data-source>myDS</jta-data-source> 204 <class>org.jpwh.model</class> 205 <class>org.jpwh.model.inheritance.embeddable.Measurement</class> 206 <class>org.jpwh.model.inheritance.embeddable.Dimensions</class> 207 <class>org.jpwh.model.inheritance.embeddable.Weight</class> 208 <class>org.jpwh.model.inheritance.embeddable.Item</class> 209 <exclude-unlisted-classes>true</exclude-unlisted-classes> 210 </persistence-unit> 211 212 <persistence-unit name="PolymorphicManyToOnePU"> 213 <jta-data-source>myDS</jta-data-source> 214 <class>org.jpwh.model</class> 215 <class>org.jpwh.model.inheritance.associations.manytoone.BillingDetails</class> 216 <class>org.jpwh.model.inheritance.associations.manytoone.BankAccount</class> 217 <class>org.jpwh.model.inheritance.associations.manytoone.CreditCard</class> 218 <class>org.jpwh.model.inheritance.associations.manytoone.User</class> 219 <exclude-unlisted-classes>true</exclude-unlisted-classes> 220 </persistence-unit> 221 222 <persistence-unit name="PolymorphicOneToManyPU"> 223 <jta-data-source>myDS</jta-data-source> 224 <class>org.jpwh.model</class> 225 <class>org.jpwh.model.inheritance.associations.onetomany.BillingDetails</class> 226 <class>org.jpwh.model.inheritance.associations.onetomany.BankAccount</class> 227 <class>org.jpwh.model.inheritance.associations.onetomany.CreditCard</class> 228 <class>org.jpwh.model.inheritance.associations.onetomany.User</class> 229 <exclude-unlisted-classes>true</exclude-unlisted-classes> 230 </persistence-unit> 231 232 <persistence-unit name="AdvancedPU"> 233 <jta-data-source>myDS</jta-data-source> 234 <class>org.jpwh.model</class> 235 <class>org.jpwh.model.advanced.Item</class> 236 <class>org.jpwh.model.advanced.Bid</class> 237 <class>org.jpwh.model.advanced.User</class> 238 <class>org.jpwh.model.advanced.Address</class> 239 <class>org.jpwh.model.advanced.City</class> 240 <class>org.jpwh.model.advanced.ItemBidSummary</class> 241 <exclude-unlisted-classes>true</exclude-unlisted-classes> 242 </persistence-unit> 243 244 <persistence-unit name="CustomSchemaPU"> 245 <jta-data-source>myDS</jta-data-source> 246 <class>org.jpwh.model</class> 247 <class>org.jpwh.model.complexschemas.custom.Bid</class> 248 <class>org.jpwh.model.complexschemas.custom.Item</class> 249 <class>org.jpwh.model.complexschemas.custom.User</class> 250 <exclude-unlisted-classes>true</exclude-unlisted-classes> 251 <properties> 252 <!-- 253 By default, Hibernate expects one SQL statement per line in scripts. This 254 switches to the more convenient multi-line extractor. SQL statements in 255 scripts are then terminated with semicolon. You can write your own 256 <code>org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor</code> 257 implementation if you want to handle the SQL script in a different way. 258 --> 259 <property name="hibernate.hbm2ddl.import_files_sql_extractor" 260 value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor"/> 261 262 <!-- 263 264 This property defines when the create and drop scripts should be executed. 265 Our custom SQL scripts will contain <code>CREATE DOMAIN</code> statements, which 266 have to be executed before the tables using these domains are created. With 267 these settings the schema generator will run the create script first, before 268 reading your ORM metadata (annotations, XML files) and creating the tables. 269 The drop script will execute after Hibernate drops the tables, giving us 270 a chance to clean up anything we created. Other options are 271 <code>metadata</code> (ignore custom script sources) and 272 <code>script</code> (only use custom script source, ignore ORM metadata in 273 annotations and XML files). 274 --> 275 <property name="javax.persistence.schema-generation.create-source" 276 value="script-then-metadata"/> 277 <property name="javax.persistence.schema-generation.drop-source" 278 value="metadata-then-script"/> 279 280 <!-- 281 282 The location of the custom SQL script for creation of the schema. The 283 path is either (a) the location of the script resource on the classpath 284 or (b) the location of the script as a <code>file://</code> URL or 285 (c) if neither (a) or (b) match, the absolute or relative file path on 286 the local file system. This example uses (a). 287 --> 288 <property name="javax.persistence.schema-generation.create-script-source" 289 value="complexschemas/CreateScript.sql.txt"/> 290 291 <!-- 292 293 The custom SQL script for dropping the schema. 294 --> 295 <property name="javax.persistence.schema-generation.drop-script-source" 296 value="complexschemas/DropScript.sql.txt"/> 297 298 <!-- 299 300 This load script runs after the tables have been created. 301 --> 302 <property name="javax.persistence.sql-load-script-source" 303 value="complexschemas/LoadScript.sql.txt"/> 304 </properties> 305 </persistence-unit> 306 307 <persistence-unit name="NaturalPrimaryKeyPU"> 308 <jta-data-source>myDS</jta-data-source> 309 <class>org.jpwh.model.complexschemas.naturalprimarykey.User</class> 310 <exclude-unlisted-classes>true</exclude-unlisted-classes> 311 </persistence-unit> 312 313 <persistence-unit name="CompositeKeyEmbeddedIdPU"> 314 <jta-data-source>myDS</jta-data-source> 315 <class>org.jpwh.model.complexschemas.compositekey.embedded.User</class> 316 <exclude-unlisted-classes>true</exclude-unlisted-classes> 317 </persistence-unit> 318 319 <persistence-unit name="CompositeKeyMapsIdPU"> 320 <jta-data-source>myDS</jta-data-source> 321 <class>org.jpwh.model</class> 322 <class>org.jpwh.model.complexschemas.compositekey.mapsid.User</class> 323 <class>org.jpwh.model.complexschemas.compositekey.mapsid.Department</class> 324 <exclude-unlisted-classes>true</exclude-unlisted-classes> 325 </persistence-unit> 326 327 <persistence-unit name="CompositeKeyReadOnlyPU"> 328 <jta-data-source>myDS</jta-data-source> 329 <class>org.jpwh.model</class> 330 <class>org.jpwh.model.complexschemas.compositekey.readonly.User</class> 331 <class>org.jpwh.model.complexschemas.compositekey.readonly.Department</class> 332 <exclude-unlisted-classes>true</exclude-unlisted-classes> 333 </persistence-unit> 334 335 <persistence-unit name="CompositeKeyManyToOnePU"> 336 <jta-data-source>myDS</jta-data-source> 337 <class>org.jpwh.model</class> 338 <class>org.jpwh.model.complexschemas.compositekey.manytoone.User</class> 339 <class>org.jpwh.model.complexschemas.compositekey.manytoone.Item</class> 340 <exclude-unlisted-classes>true</exclude-unlisted-classes> 341 </persistence-unit> 342 343 <persistence-unit name="NaturalForeignKeyPU"> 344 <jta-data-source>myDS</jta-data-source> 345 <class>org.jpwh.model</class> 346 <class>org.jpwh.model.complexschemas.naturalforeignkey.User</class> 347 <class>org.jpwh.model.complexschemas.naturalforeignkey.Item</class> 348 <exclude-unlisted-classes>true</exclude-unlisted-classes> 349 </persistence-unit> 350 351 <persistence-unit name="SecondaryTablePU"> 352 <jta-data-source>myDS</jta-data-source> 353 <class>org.jpwh.model</class> 354 <class>org.jpwh.model.complexschemas.secondarytable.User</class> 355 <exclude-unlisted-classes>true</exclude-unlisted-classes> 356 </persistence-unit> 357 358 <persistence-unit name="CustomSQLPU"> 359 <jta-data-source>myDS</jta-data-source> 360 <class>org.jpwh.model</class> 361 <class>org.jpwh.model.customsql.Category</class> 362 <class>org.jpwh.model.customsql.Bid</class> 363 <class>org.jpwh.model.customsql.Item</class> 364 <class>org.jpwh.model.customsql.User</class> 365 <exclude-unlisted-classes>true</exclude-unlisted-classes> 366 </persistence-unit> 367 368 <persistence-unit name="CRUDProceduresPU"> 369 <jta-data-source>myDS</jta-data-source> 370 <class>org.jpwh.model</class> 371 <class>org.jpwh.model.customsql.procedures.User</class> 372 <exclude-unlisted-classes>true</exclude-unlisted-classes> 373 </persistence-unit> 374 375 <persistence-unit name="SetOfStringsPU"> 376 <jta-data-source>myDS</jta-data-source> 377 <class>org.jpwh.model</class> 378 <class>org.jpwh.model.collections.setofstrings.Item</class> 379 <exclude-unlisted-classes>true</exclude-unlisted-classes> 380 </persistence-unit> 381 382 <persistence-unit name="BagOfStringsPU"> 383 <jta-data-source>myDS</jta-data-source> 384 <class>org.jpwh.model</class> 385 <class>org.jpwh.model.collections.bagofstrings.Item</class> 386 <exclude-unlisted-classes>true</exclude-unlisted-classes> 387 </persistence-unit> 388 389 <persistence-unit name="ListOfStringsPU"> 390 <jta-data-source>myDS</jta-data-source> 391 <class>org.jpwh.model</class> 392 <class>org.jpwh.model.collections.listofstrings.Item</class> 393 <exclude-unlisted-classes>true</exclude-unlisted-classes> 394 </persistence-unit> 395 396 <persistence-unit name="MapOfStringsPU"> 397 <jta-data-source>myDS</jta-data-source> 398 <class>org.jpwh.model</class> 399 <class>org.jpwh.model.collections.mapofstrings.Item</class> 400 <exclude-unlisted-classes>true</exclude-unlisted-classes> 401 </persistence-unit> 402 403 <persistence-unit name="SortedSetOfStringsPU"> 404 <jta-data-source>myDS</jta-data-source> 405 <class>org.jpwh.model</class> 406 <class>org.jpwh.model.collections.sortedsetofstrings.Item</class> 407 <exclude-unlisted-classes>true</exclude-unlisted-classes> 408 </persistence-unit> 409 410 <persistence-unit name="SortedMapOfStringsPU"> 411 <jta-data-source>myDS</jta-data-source> 412 <class>org.jpwh.model</class> 413 <class>org.jpwh.model.collections.sortedmapofstrings.Item</class> 414 <exclude-unlisted-classes>true</exclude-unlisted-classes> 415 </persistence-unit> 416 417 <persistence-unit name="SetOfStringsOrderByPU"> 418 <jta-data-source>myDS</jta-data-source> 419 <class>org.jpwh.model</class> 420 <class>org.jpwh.model.collections.setofstringsorderby.Item</class> 421 <exclude-unlisted-classes>true</exclude-unlisted-classes> 422 </persistence-unit> 423 424 <persistence-unit name="BagOfStringsOrderByPU"> 425 <jta-data-source>myDS</jta-data-source> 426 <class>org.jpwh.model</class> 427 <class>org.jpwh.model.collections.bagofstringsorderby.Item</class> 428 <exclude-unlisted-classes>true</exclude-unlisted-classes> 429 </persistence-unit> 430 431 <persistence-unit name="MapOfStringsOrderByPU"> 432 <jta-data-source>myDS</jta-data-source> 433 <class>org.jpwh.model</class> 434 <class>org.jpwh.model.collections.mapofstringsorderby.Item</class> 435 <exclude-unlisted-classes>true</exclude-unlisted-classes> 436 </persistence-unit> 437 438 <persistence-unit name="SetOfEmbeddablesPU"> 439 <jta-data-source>myDS</jta-data-source> 440 <class>org.jpwh.model</class> 441 <class>org.jpwh.model.collections.setofembeddables.Item</class> 442 <class>org.jpwh.model.collections.setofembeddables.Image</class> 443 <exclude-unlisted-classes>true</exclude-unlisted-classes> 444 </persistence-unit> 445 446 <persistence-unit name="SetOfEmbeddablesOrderByPU"> 447 <jta-data-source>myDS</jta-data-source> 448 <class>org.jpwh.model</class> 449 <class>org.jpwh.model.collections.setofembeddablesorderby.Item</class> 450 <class>org.jpwh.model.collections.setofembeddablesorderby.Image</class> 451 <exclude-unlisted-classes>true</exclude-unlisted-classes> 452 </persistence-unit> 453 454 <persistence-unit name="BagOfEmbeddablesPU"> 455 <jta-data-source>myDS</jta-data-source> 456 <class>org.jpwh.model</class> 457 <class>org.jpwh.model.collections.bagofembeddables.Item</class> 458 <class>org.jpwh.model.collections.bagofembeddables.Image</class> 459 <exclude-unlisted-classes>true</exclude-unlisted-classes> 460 </persistence-unit> 461 462 <persistence-unit name="MapOfStringsEmbeddablesPU"> 463 <jta-data-source>myDS</jta-data-source> 464 <class>org.jpwh.model</class> 465 <class>org.jpwh.model.collections.mapofstringsembeddables.Item</class> 466 <class>org.jpwh.model.collections.mapofstringsembeddables.Image</class> 467 <exclude-unlisted-classes>true</exclude-unlisted-classes> 468 </persistence-unit> 469 470 <persistence-unit name="MapOfEmbeddablesPU"> 471 <jta-data-source>myDS</jta-data-source> 472 <class>org.jpwh.model</class> 473 <class>org.jpwh.model.collections.mapofembeddables.Item</class> 474 <class>org.jpwh.model.collections.mapofembeddables.Image</class> 475 <class>org.jpwh.model.collections.mapofembeddables.Filename</class> 476 <exclude-unlisted-classes>true</exclude-unlisted-classes> 477 </persistence-unit> 478 479 <persistence-unit name="EmbeddableSetOfStringsPU"> 480 <jta-data-source>myDS</jta-data-source> 481 <class>org.jpwh.model</class> 482 <class>org.jpwh.model.collections.embeddablesetofstrings.User</class> 483 <exclude-unlisted-classes>true</exclude-unlisted-classes> 484 </persistence-unit> 485 486 <persistence-unit name="OneToManyBidirectionalPU"> 487 <jta-data-source>myDS</jta-data-source> 488 <class>org.jpwh.model</class> 489 <class>org.jpwh.model.associations.onetomany.bidirectional.Item</class> 490 <class>org.jpwh.model.associations.onetomany.bidirectional.Bid</class> 491 <exclude-unlisted-classes>true</exclude-unlisted-classes> 492 </persistence-unit> 493 494 <persistence-unit name="OneToManyCascadePersistPU"> 495 <jta-data-source>myDS</jta-data-source> 496 <class>org.jpwh.model</class> 497 <class>org.jpwh.model.associations.onetomany.cascadepersist.Item</class> 498 <class>org.jpwh.model.associations.onetomany.cascadepersist.Bid</class> 499 <exclude-unlisted-classes>true</exclude-unlisted-classes> 500 </persistence-unit> 501 502 <persistence-unit name="OneToManyCascadeRemovePU"> 503 <jta-data-source>myDS</jta-data-source> 504 <class>org.jpwh.model</class> 505 <class>org.jpwh.model.associations.onetomany.cascaderemove.Item</class> 506 <class>org.jpwh.model.associations.onetomany.cascaderemove.Bid</class> 507 <exclude-unlisted-classes>true</exclude-unlisted-classes> 508 </persistence-unit> 509 510 <persistence-unit name="OneToManyOrphanRemovalPU"> 511 <jta-data-source>myDS</jta-data-source> 512 <class>org.jpwh.model</class> 513 <class>org.jpwh.model.associations.onetomany.orphanremoval.Item</class> 514 <class>org.jpwh.model.associations.onetomany.orphanremoval.Bid</class> 515 <class>org.jpwh.model.associations.onetomany.orphanremoval.User</class> 516 <exclude-unlisted-classes>true</exclude-unlisted-classes> 517 </persistence-unit> 518 519 <persistence-unit name="OneToManyOnDeleteCascadePU"> 520 <jta-data-source>myDS</jta-data-source> 521 <class>org.jpwh.model</class> 522 <class>org.jpwh.model.associations.onetomany.ondeletecascade.Item</class> 523 <class>org.jpwh.model.associations.onetomany.ondeletecascade.Bid</class> 524 <exclude-unlisted-classes>true</exclude-unlisted-classes> 525 </persistence-unit> 526 527 <persistence-unit name="OneToManyBagPU"> 528 <jta-data-source>myDS</jta-data-source> 529 <class>org.jpwh.model</class> 530 <class>org.jpwh.model.associations.onetomany.bag.Item</class> 531 <class>org.jpwh.model.associations.onetomany.bag.Bid</class> 532 <exclude-unlisted-classes>true</exclude-unlisted-classes> 533 </persistence-unit> 534 535 <persistence-unit name="OneToManyListPU"> 536 <jta-data-source>myDS</jta-data-source> 537 <class>org.jpwh.model</class> 538 <class>org.jpwh.model.associations.onetomany.list.Item</class> 539 <class>org.jpwh.model.associations.onetomany.list.Bid</class> 540 <exclude-unlisted-classes>true</exclude-unlisted-classes> 541 </persistence-unit> 542 543 <persistence-unit name="OneToManyJoinTablePU"> 544 <jta-data-source>myDS</jta-data-source> 545 <class>org.jpwh.model</class> 546 <class>org.jpwh.model.associations.onetomany.jointable.Item</class> 547 <class>org.jpwh.model.associations.onetomany.jointable.User</class> 548 <exclude-unlisted-classes>true</exclude-unlisted-classes> 549 </persistence-unit> 550 551 <persistence-unit name="OneToManyEmbeddablePU"> 552 <jta-data-source>myDS</jta-data-source> 553 <class>org.jpwh.model</class> 554 <class>org.jpwh.model.associations.onetomany.embeddable.User</class> 555 <class>org.jpwh.model.associations.onetomany.embeddable.Shipment</class> 556 <exclude-unlisted-classes>true</exclude-unlisted-classes> 557 </persistence-unit> 558 559 <persistence-unit name="OneToManyEmbeddableJoinTablePU"> 560 <jta-data-source>myDS</jta-data-source> 561 <class>org.jpwh.model</class> 562 <class>org.jpwh.model.associations.onetomany.embeddablejointable.User</class> 563 <class>org.jpwh.model.associations.onetomany.embeddablejointable.Shipment</class> 564 <exclude-unlisted-classes>true</exclude-unlisted-classes> 565 </persistence-unit> 566 567 <persistence-unit name="OneToOneSharedPrimaryKeyPU"> 568 <jta-data-source>myDS</jta-data-source> 569 <class>org.jpwh.model</class> 570 <class>org.jpwh.model.associations.onetoone.sharedprimarykey.User</class> 571 <class>org.jpwh.model.associations.onetoone.sharedprimarykey.Address</class> 572 <exclude-unlisted-classes>true</exclude-unlisted-classes> 573 </persistence-unit> 574 575 <persistence-unit name="OneToOneForeignGeneratorPU"> 576 <jta-data-source>myDS</jta-data-source> 577 <class>org.jpwh.model</class> 578 <class>org.jpwh.model.associations.onetoone.foreigngenerator.User</class> 579 <class>org.jpwh.model.associations.onetoone.foreigngenerator.Address</class> 580 <exclude-unlisted-classes>true</exclude-unlisted-classes> 581 </persistence-unit> 582 583 <persistence-unit name="OneToOneForeignKeyPU"> 584 <jta-data-source>myDS</jta-data-source> 585 <class>org.jpwh.model</class> 586 <class>org.jpwh.model.associations.onetoone.foreignkey.User</class> 587 <class>org.jpwh.model.associations.onetoone.foreignkey.Address</class> 588 <exclude-unlisted-classes>true</exclude-unlisted-classes> 589 </persistence-unit> 590 591 <persistence-unit name="OneToOneJoinTablePU"> 592 <jta-data-source>myDS</jta-data-source> 593 <class>org.jpwh.model</class> 594 <class>org.jpwh.model.associations.onetoone.jointable.Item</class> 595 <class>org.jpwh.model.associations.onetoone.jointable.Shipment</class> 596 <exclude-unlisted-classes>true</exclude-unlisted-classes> 597 </persistence-unit> 598 599 <persistence-unit name="ManyToManyBidirectionalPU"> 600 <jta-data-source>myDS</jta-data-source> 601 <class>org.jpwh.model</class> 602 <class>org.jpwh.model.associations.manytomany.bidirectional.Category</class> 603 <class>org.jpwh.model.associations.manytomany.bidirectional.Item</class> 604 <exclude-unlisted-classes>true</exclude-unlisted-classes> 605 </persistence-unit> 606 607 <persistence-unit name="ManyToManyLinkEntityPU"> 608 <jta-data-source>myDS</jta-data-source> 609 <class>org.jpwh.model</class> 610 <class>org.jpwh.model.associations.manytomany.linkentity.Category</class> 611 <class>org.jpwh.model.associations.manytomany.linkentity.Item</class> 612 <class>org.jpwh.model.associations.manytomany.linkentity.CategorizedItem</class> 613 <exclude-unlisted-classes>true</exclude-unlisted-classes> 614 </persistence-unit> 615 616 <persistence-unit name="ManyToManyTernaryPU"> 617 <jta-data-source>myDS</jta-data-source> 618 <class>org.jpwh.model</class> 619 <class>org.jpwh.model.associations.manytomany.ternary.Category</class> 620 <class>org.jpwh.model.associations.manytomany.ternary.Item</class> 621 <class>org.jpwh.model.associations.manytomany.ternary.User</class> 622 <class>org.jpwh.model.associations.manytomany.ternary.CategorizedItem</class> 623 <exclude-unlisted-classes>true</exclude-unlisted-classes> 624 </persistence-unit> 625 626 <persistence-unit name="MapsMapKeyPU"> 627 <jta-data-source>myDS</jta-data-source> 628 <class>org.jpwh.model</class> 629 <class>org.jpwh.model.associations.maps.mapkey.Item</class> 630 <class>org.jpwh.model.associations.maps.mapkey.Bid</class> 631 <exclude-unlisted-classes>true</exclude-unlisted-classes> 632 </persistence-unit> 633 634 <persistence-unit name="MapsTernaryPU"> 635 <jta-data-source>myDS</jta-data-source> 636 <class>org.jpwh.model</class> 637 <class>org.jpwh.model.associations.maps.ternary.Item</class> 638 <class>org.jpwh.model.associations.maps.ternary.Category</class> 639 <class>org.jpwh.model.associations.maps.ternary.User</class> 640 <exclude-unlisted-classes>true</exclude-unlisted-classes> 641 </persistence-unit> 642 643 <persistence-unit name="ConcurrencyVersioningPU"> 644 <jta-data-source>myDS</jta-data-source> 645 <class>org.jpwh.model</class> 646 <class>org.jpwh.model.concurrency.version.Item</class> 647 <class>org.jpwh.model.concurrency.version.Bid</class> 648 <class>org.jpwh.model.concurrency.version.Category</class> 649 <exclude-unlisted-classes>true</exclude-unlisted-classes> 650 </persistence-unit> 651 652 <persistence-unit name="ConcurrencyVersioningTimestampPU"> 653 <jta-data-source>myDS</jta-data-source> 654 <class>org.jpwh.model</class> 655 <class>org.jpwh.model.concurrency.versiontimestamp.Item</class> 656 <exclude-unlisted-classes>true</exclude-unlisted-classes> 657 </persistence-unit> 658 659 <persistence-unit name="ConcurrencyVersioningAllPU"> 660 <jta-data-source>myDS</jta-data-source> 661 <class>org.jpwh.model</class> 662 <class>org.jpwh.model.concurrency.versionall.Item</class> 663 <exclude-unlisted-classes>true</exclude-unlisted-classes> 664 </persistence-unit> 665 666 <persistence-unit name="ConversationPU"> 667 <jta-data-source>myDS</jta-data-source> 668 <class>org.jpwh.model</class> 669 <class>org.jpwh.model.conversation.User</class> 670 <class>org.jpwh.model.conversation.Item</class> 671 <class>org.jpwh.model.conversation.Image</class> 672 <exclude-unlisted-classes>true</exclude-unlisted-classes> 673 </persistence-unit> 674 675 <persistence-unit name="FilteringCascadePU"> 676 <jta-data-source>myDS</jta-data-source> 677 <mapping-file>filtering/DefaultCascadePersist.xml</mapping-file> 678 <class>org.jpwh.model</class> 679 <class>org.jpwh.model.filtering.cascade.Item</class> 680 <class>org.jpwh.model.filtering.cascade.Bid</class> 681 <class>org.jpwh.model.filtering.cascade.User</class> 682 <class>org.jpwh.model.filtering.cascade.BillingDetails</class> 683 <class>org.jpwh.model.filtering.cascade.CreditCard</class> 684 <class>org.jpwh.model.filtering.cascade.BankAccount</class> 685 <exclude-unlisted-classes>true</exclude-unlisted-classes> 686 </persistence-unit> 687 688 <persistence-unit name="FilteringCallbackPU"> 689 <jta-data-source>myDS</jta-data-source> 690 <mapping-file>filtering/EventListeners.xml</mapping-file> 691 <class>org.jpwh.model</class> 692 <class>org.jpwh.model.filtering.callback.Item</class> 693 <class>org.jpwh.model.filtering.callback.User</class> 694 <exclude-unlisted-classes>true</exclude-unlisted-classes> 695 </persistence-unit> 696 697 <persistence-unit name="FilteringInterceptorPU"> 698 <jta-data-source>myDS</jta-data-source> 699 <class>org.jpwh.model</class> 700 <class>org.jpwh.model.filtering.interceptor.Item</class> 701 <class>org.jpwh.model.filtering.interceptor.User</class> 702 <class>org.jpwh.model.filtering.interceptor.AuditLogRecord</class> 703 <exclude-unlisted-classes>true</exclude-unlisted-classes> 704 <properties> 705 <property name="hibernate.ejb.event.load" 706 value="org.jpwh.test.filtering.SecurityLoadListener"/> 707 </properties> 708 </persistence-unit> 709 710 <persistence-unit name="FilteringEnversPU"> 711 <jta-data-source>myDS</jta-data-source> 712 <class>org.jpwh.model</class> 713 <class>org.jpwh.model.filtering.envers.Item</class> 714 <class>org.jpwh.model.filtering.envers.User</class> 715 <class>org.jpwh.model.filtering.envers.Bid</class> 716 <exclude-unlisted-classes>true</exclude-unlisted-classes> 717 </persistence-unit> 718 719 <persistence-unit name="FilteringDynamicPU"> 720 <jta-data-source>myDS</jta-data-source> 721 <class>org.jpwh.model</class> 722 <class>org.jpwh.model.filtering.dynamic</class> 723 <class>org.jpwh.model.filtering.dynamic.User</class> 724 <class>org.jpwh.model.filtering.dynamic.Item</class> 725 <class>org.jpwh.model.filtering.dynamic.Category</class> 726 <exclude-unlisted-classes>true</exclude-unlisted-classes> 727 </persistence-unit> 728 729 <persistence-unit name="QueryingPU"> 730 <jta-data-source>myDS</jta-data-source> 731 <mapping-file>querying/ExternalizedQueries.xml</mapping-file> 732 <mapping-file>querying/Selection.xml</mapping-file> 733 <mapping-file>querying/Restriction.xml</mapping-file> 734 <mapping-file>querying/Projection.xml</mapping-file> 735 <mapping-file>querying/Joins.xml</mapping-file> 736 <mapping-file>querying/Grouping.xml</mapping-file> 737 <mapping-file>querying/Subselects.xml</mapping-file> 738 <mapping-file>querying/NativeQueries.xml</mapping-file> 739 <class>org.jpwh.model</class> 740 <class>org.jpwh.model.querying</class> 741 <class>org.jpwh.model.querying.Category</class> 742 <class>org.jpwh.model.querying.Item</class> 743 <class>org.jpwh.model.querying.Bid</class> 744 <class>org.jpwh.model.querying.Image</class> 745 <class>org.jpwh.model.querying.User</class> 746 <class>org.jpwh.model.querying.Address</class> 747 <class>org.jpwh.model.querying.LogRecord</class> 748 <class>org.jpwh.model.inheritance.tableperclass.BillingDetails</class> 749 <class>org.jpwh.model.inheritance.tableperclass.CreditCard</class> 750 <class>org.jpwh.model.inheritance.tableperclass.BankAccount</class> 751 <exclude-unlisted-classes>true</exclude-unlisted-classes> 752 <properties> 753 <!-- You typically want portable, predictable sorting for nulls in your app --> 754 <property name="hibernate.order_by.default_null_ordering" value="first"/> 755 </properties> 756 </persistence-unit> 757 758 <persistence-unit name="FetchingProxyPU"> 759 <jta-data-source>myDS</jta-data-source> 760 <class>org.jpwh.model</class> 761 <class>org.jpwh.model.fetching.proxy.Category</class> 762 <class>org.jpwh.model.fetching.proxy.Item</class> 763 <class>org.jpwh.model.fetching.proxy.Bid</class> 764 <class>org.jpwh.model.fetching.proxy.User</class> 765 <exclude-unlisted-classes>true</exclude-unlisted-classes> 766 </persistence-unit> 767 768 <persistence-unit name="FetchingInterceptionPU"> 769 <jta-data-source>myDS</jta-data-source> 770 <class>org.jpwh.model</class> 771 <class>org.jpwh.model.fetching.interception.Item</class> 772 <class>org.jpwh.model.fetching.interception.User</class> 773 <exclude-unlisted-classes>true</exclude-unlisted-classes> 774 </persistence-unit> 775 776 <persistence-unit name="FetchingEagerJoinPU"> 777 <jta-data-source>myDS</jta-data-source> 778 <class>org.jpwh.model</class> 779 <class>org.jpwh.model.fetching.eagerjoin.Item</class> 780 <class>org.jpwh.model.fetching.eagerjoin.User</class> 781 <class>org.jpwh.model.fetching.eagerjoin.Bid</class> 782 <exclude-unlisted-classes>true</exclude-unlisted-classes> 783 </persistence-unit> 784 785 <persistence-unit name="FetchingNPlusOneSelectsPU"> 786 <jta-data-source>myDS</jta-data-source> 787 <class>org.jpwh.model</class> 788 <class>org.jpwh.model.fetching.nplusoneselects.Item</class> 789 <class>org.jpwh.model.fetching.nplusoneselects.User</class> 790 <class>org.jpwh.model.fetching.nplusoneselects.Bid</class> 791 <exclude-unlisted-classes>true</exclude-unlisted-classes> 792 </persistence-unit> 793 794 <persistence-unit name="FetchingCartesianProductPU"> 795 <jta-data-source>myDS</jta-data-source> 796 <class>org.jpwh.model</class> 797 <class>org.jpwh.model.fetching.cartesianproduct.Item</class> 798 <class>org.jpwh.model.fetching.cartesianproduct.User</class> 799 <class>org.jpwh.model.fetching.cartesianproduct.Bid</class> 800 <exclude-unlisted-classes>true</exclude-unlisted-classes> 801 </persistence-unit> 802 803 <persistence-unit name="FetchingBatchPU"> 804 <jta-data-source>myDS</jta-data-source> 805 <class>org.jpwh.model</class> 806 <class>org.jpwh.model.fetching.batch.Item</class> 807 <class>org.jpwh.model.fetching.batch.User</class> 808 <class>org.jpwh.model.fetching.batch.Bid</class> 809 <exclude-unlisted-classes>true</exclude-unlisted-classes> 810 </persistence-unit> 811 812 <persistence-unit name="FetchingSubselectPU"> 813 <jta-data-source>myDS</jta-data-source> 814 <class>org.jpwh.model</class> 815 <class>org.jpwh.model.fetching.subselect.Item</class> 816 <class>org.jpwh.model.fetching.subselect.User</class> 817 <class>org.jpwh.model.fetching.subselect.Bid</class> 818 <exclude-unlisted-classes>true</exclude-unlisted-classes> 819 </persistence-unit> 820 821 <persistence-unit name="FetchingEagerSelectPU"> 822 <jta-data-source>myDS</jta-data-source> 823 <class>org.jpwh.model</class> 824 <class>org.jpwh.model.fetching.eagerselect.Item</class> 825 <class>org.jpwh.model.fetching.eagerselect.User</class> 826 <class>org.jpwh.model.fetching.eagerselect.Bid</class> 827 <exclude-unlisted-classes>true</exclude-unlisted-classes> 828 </persistence-unit> 829 830 <persistence-unit name="FetchingProfilePU"> 831 <jta-data-source>myDS</jta-data-source> 832 <class>org.jpwh.model</class> 833 <class>org.jpwh.model.fetching.profile</class> 834 <class>org.jpwh.model.fetching.profile.Item</class> 835 <class>org.jpwh.model.fetching.profile.User</class> 836 <class>org.jpwh.model.fetching.profile.Bid</class> 837 <exclude-unlisted-classes>true</exclude-unlisted-classes> 838 </persistence-unit> 839 840 <persistence-unit name="FetchingReadOnlyPU"> 841 <jta-data-source>myDS</jta-data-source> 842 <class>org.jpwh.model</class> 843 <class>org.jpwh.model.fetching.readonly.Item</class> 844 <class>org.jpwh.model.fetching.readonly.User</class> 845 <class>org.jpwh.model.fetching.readonly.Bid</class> 846 <exclude-unlisted-classes>true</exclude-unlisted-classes> 847 </persistence-unit> 848 849 <persistence-unit name="FetchingFetchLoadGraphPU"> 850 <jta-data-source>myDS</jta-data-source> 851 <class>org.jpwh.model</class> 852 <class>org.jpwh.model.fetching.fetchloadgraph.Item</class> 853 <class>org.jpwh.model.fetching.fetchloadgraph.User</class> 854 <class>org.jpwh.model.fetching.fetchloadgraph.Bid</class> 855 <exclude-unlisted-classes>true</exclude-unlisted-classes> 856 </persistence-unit> 857 858 <persistence-unit name="BulkBatchPU"> 859 <jta-data-source>myDS</jta-data-source> 860 <class>org.jpwh.model.bulkbatch</class> 861 <!-- Note the special ID generator in this package --> 862 <class>org.jpwh.model.bulkbatch.Item</class> 863 <class>org.jpwh.model.bulkbatch.User</class> 864 <class>org.jpwh.model.bulkbatch.Bid</class> 865 <class>org.jpwh.model.bulkbatch.BillingDetails</class> 866 <class>org.jpwh.model.bulkbatch.CreditCard</class> 867 <class>org.jpwh.model.bulkbatch.BankAccount</class> 868 <class>org.jpwh.model.bulkbatch.StolenCreditCard</class> 869 <exclude-unlisted-classes>true</exclude-unlisted-classes> 870 <properties> 871 <property name="hibernate.jdbc.batch_size" value="100"/> 872 <property name="hibernate.jdbc.batch_versioned_data" value="true"/> 873 <property name="hibernate.order_inserts" value="true"/> 874 </properties> 875 </persistence-unit> 876 877 <persistence-unit name="CachePU"> 878 <jta-data-source>myDS</jta-data-source> 879 <class>org.jpwh.model</class> 880 <class>org.jpwh.model.cache.Item</class> 881 <class>org.jpwh.model.cache.Bid</class> 882 <class>org.jpwh.model.cache.User</class> 883 <exclude-unlisted-classes>true</exclude-unlisted-classes> 884 <!-- 885 The shared cache mode controls how entity classes of this persistence 886 unit become cacheable. Usually you prefer to enable caching selectively 887 for only some entity classes. Other options are 888 <code>DISABLE_SELECTIVE</code>, <code>ALL</code>, and <code>NONE</code>. 889 --> 890 <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> 891 <properties> 892 <!-- 893 Hibernate's second-level cache system has to be enabled 894 explicitly, as it is not enabled by default. You can separately 895 enable the query result cache; it's disabled by default as well. 896 --> 897 <property name="hibernate.cache.use_second_level_cache" 898 value="true"/> 899 <property name="hibernate.cache.use_query_cache" 900 value="true"/> 901 902 <!-- 903 Next, you pick a provider for the second-level cache system. For EHCache, 904 add the <code>org.hibernate:hibernate-ehcache</code> Maven artifact 905 dependency to your classpath. Then, pick how Hibernate uses EHCache with this 906 region factory setting; here we tell Hibernate to manage a single 907 EHCache instance internally as the second-level cache provider. 908 --> 909 <property name="hibernate.cache.region.factory_class" 910 value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/> 911 912 <!-- 913 Hibernate will pass this property along to EHCache when the provider 914 is started, setting the location of the EHCache configuration file. All 915 physical cache settings for cache regions are in this file. 916 --> 917 <property name="net.sf.ehcache.configurationResourceName" 918 value="/cache/ehcache.xml"/> 919 920 <!-- 921 This setting controls how Hibernate disassembles and assembles 922 entity state when data is stored and loaded from the second-level 923 cache. The "structured" cache entry format is less efficient but 924 necessary in a clustered environment. For a non-clustered 925 second-level cache, like our singleton EHCache on this JVM, you 926 can disable this setting and a more efficient format is used. 927 --> 928 <property name="hibernate.cache.use_structured_entries" 929 value="false"/> 930 931 <!-- 932 While you experiment with the second-level cache, you usually 933 want to see and examine what's happening behind the scenes. Hibernate 934 has a statistics collector and an API to access these statistics. For 935 performance reasons, it is disabled by default (and should be 936 disabled in production). 937 --> 938 <property name="hibernate.generate_statistics" 939 value="true"/> 940 </properties> 941 </persistence-unit> 942 943 </persistence>
For the “Hello World” application, you delegate database connection handling to a Java Transaction API ( JTA ) provider, the open source Bitronix project. Bitronix offers connection pooling with a managed java.sql.DataSource and the standard javax.transaction.UserTransaction API in any Java SE environment. Bitronix binds
these objects into JNDI , and Hibernate interfaces automatically with Bitronix through JNDI lookups.
2.jndi.properties(这个文件似乎不起作用)
# Bitronix has a built-in JNDI context, for binding and looking up datasources java.naming.factory.initial=bitronix.tm.jndi.BitronixInitialContextFactory
四、测试文件
1.
1 package org.jpwh.helloworld; 2 3 import org.jpwh.env.TransactionManagerTest; 4 import org.jpwh.model.helloworld.Message; 5 import org.testng.annotations.Test; 6 7 import javax.persistence.EntityManager; 8 import javax.persistence.EntityManagerFactory; 9 import javax.persistence.Persistence; 10 import javax.transaction.UserTransaction; 11 import java.util.List; 12 13 import static org.testng.Assert.assertEquals; 14 15 public class HelloWorldJPA extends TransactionManagerTest { 16 17 @Test 18 public void storeLoadMessage() throws Exception { 19 20 EntityManagerFactory emf = 21 Persistence.createEntityManagerFactory("HelloWorldPU"); 22 23 try { 24 { 25 /* 26 Get access to the standard transaction API <code>UserTransaction</code> and 27 begin a transaction on this thread of execution. 28 */ 29 UserTransaction tx = TM.getUserTransaction(); 30 tx.begin(); 31 32 /* 33 Begin a new session with the database by creating an <code>EntityManager</code>, this 34 is your context for all persistence operations. 35 */ 36 EntityManager em = emf.createEntityManager(); 37 38 /* 39 Create a new instance of the mapped domain model class <code>Message</code> and 40 set its <code>text</code> property. 41 */ 42 Message message = new Message(); 43 message.setText("Hello World!"); 44 45 /* 46 Enlist the transient instance with your persistence context, you make it persistent. 47 Hibernate now knows that you wish to store that data, it doesn't necessarily call the 48 database immediately, however. 49 */ 50 em.persist(message); 51 52 /* 53 Commit the transaction, Hibernate now automatically checks the persistence context and 54 executes the necessary SQL <code>INSERT</code> statement. 55 */ 56 tx.commit(); 57 // INSERT into MESSAGE (ID, TEXT) values (1, 'Hello World!') 58 59 /* 60 If you create an <code>EntityManager</code>, you must close it. 61 */ 62 em.close(); 63 } 64 65 { 66 /* 67 Every interaction with your database should occur within explicit transaction boundaries, 68 even if you are only reading data. 69 */ 70 UserTransaction tx = TM.getUserTransaction(); 71 tx.begin(); 72 73 EntityManager em = emf.createEntityManager(); 74 75 /* 76 Execute a query to retrieve all instances of <code>Message</code> from the database. 77 */ 78 List<Message> messages = 79 em.createQuery("select m from Message m").getResultList(); 80 // SELECT * from MESSAGE 81 82 83 assertEquals(messages.size(), 1); 84 assertEquals(messages.get(0).getText(), "Hello World!"); 85 86 /* 87 You can change the value of a property, Hibernate will detect this automatically because 88 the loaded <code>Message</code> is still attached to the persistence context it was loaded in. 89 */ 90 messages.get(0).setText("Take me to your leader!"); 91 92 /* 93 On commit, Hibernate checks the persistence context for dirty state and executes the 94 SQL <code>UPDATE</code> automatically to synchronize the in-memory with the database state. 95 */ 96 tx.commit(); 97 // UPDATE MESSAGE set TEXT = 'Take me to your leader!' where ID = 1 98 99 em.close(); 100 } 101 102 } finally { 103 TM.rollback(); 104 emf.close(); 105 } 106 } 107 108 }
2.
1 package org.jpwh.helloworld; 2 3 import org.hibernate.Session; 4 import org.hibernate.SessionFactory; 5 import org.hibernate.boot.Metadata; 6 import org.hibernate.boot.MetadataBuilder; 7 import org.hibernate.boot.MetadataSources; 8 import org.hibernate.boot.registry.StandardServiceRegistryBuilder; 9 import org.hibernate.cfg.Environment; 10 import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; 11 import org.hibernate.service.ServiceRegistry; 12 import org.jpwh.env.TransactionManagerTest; 13 import org.jpwh.model.helloworld.Message; 14 import org.testng.annotations.Test; 15 16 import javax.transaction.UserTransaction; 17 import java.util.List; 18 19 import static org.testng.Assert.*; 20 21 public class HelloWorldHibernate extends TransactionManagerTest { 22 23 protected void unusedSimpleBoot() { 24 SessionFactory sessionFactory = new MetadataSources( 25 new StandardServiceRegistryBuilder() 26 .configure("hibernate.cfg.xml").build() 27 ).buildMetadata().buildSessionFactory(); 28 } 29 30 protected SessionFactory createSessionFactory() { 31 32 /* 33 This builder helps you create the immutable service registry with 34 chained method calls. 35 */ 36 StandardServiceRegistryBuilder serviceRegistryBuilder = 37 new StandardServiceRegistryBuilder(); 38 39 /* 40 Configure the services registry by applying settings. 41 */ 42 serviceRegistryBuilder 43 .applySetting("hibernate.connection.datasource", "myDS") 44 .applySetting("hibernate.format_sql", "true") 45 .applySetting("hibernate.use_sql_comments", "true") 46 .applySetting("hibernate.hbm2ddl.auto", "update"); //create-drop 47 48 // Enable JTA (this is a bit crude because Hibernate devs still believe that JTA is 49 // used only in monstrous application servers and you'll never see this code). 50 serviceRegistryBuilder.applySetting( 51 Environment.TRANSACTION_COORDINATOR_STRATEGY, 52 JtaTransactionCoordinatorBuilderImpl.class 53 ); 54 ServiceRegistry serviceRegistry = serviceRegistryBuilder.build(); 55 56 /* 57 You can only enter this configuration stage with an existing service registry. 58 */ 59 MetadataSources metadataSources = new MetadataSources(serviceRegistry); 60 61 /* 62 Add your persistent classes to the (mapping) metadata sources. 63 */ 64 metadataSources.addAnnotatedClass( 65 org.jpwh.model.helloworld.Message.class 66 ); 67 68 // Add hbm.xml mapping files 69 // metadataSources.addFile(...); 70 71 // Read all hbm.xml mapping files from a JAR 72 // metadataSources.addJar(...) 73 74 MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder(); 75 76 Metadata metadata = metadataBuilder.build(); 77 78 assertEquals(metadata.getEntityBindings().size(), 1); 79 80 SessionFactory sessionFactory = metadata.buildSessionFactory(); 81 82 return sessionFactory; 83 } 84 85 @Test 86 public void storeLoadMessage() throws Exception { 87 SessionFactory sessionFactory = createSessionFactory(); 88 try { 89 { 90 /* 91 Get access to the standard transaction API <code>UserTransaction</code> and 92 begin a transaction on this thread of execution. 93 */ 94 UserTransaction tx = TM.getUserTransaction(); 95 tx.begin(); 96 97 /* 98 Whenever you call <code>getCurrentSession()</code> in the same thread you get 99 the same <code>org.hibernate.Session</code>. It's bound automatically to the 100 ongoing transaction and is closed for you automatically when that transaction 101 commits or rolls back. 102 */ 103 Session session = sessionFactory.getCurrentSession(); 104 105 Message message = new Message(); 106 message.setText("Hello World!"); 107 108 /* 109 The native Hibernate API is very similar to the standard Java Persistence API and most methods 110 have the same name. 111 */ 112 session.persist(message); 113 114 /* 115 Hibernate synchronizes the session with the database and closes the "current" 116 session on commit of the bound transaction automatically. 117 */ 118 tx.commit(); 119 // INSERT into MESSAGE (ID, TEXT) values (1, 'Hello World!') 120 } 121 122 { 123 UserTransaction tx = TM.getUserTransaction(); 124 tx.begin(); 125 126 /* 127 A Hibernate criteria query is a type-safe programmatic way to express queries, 128 automatically translated into SQL. 129 */ 130 List<Message> messages = 131 sessionFactory.getCurrentSession().createCriteria( 132 Message.class 133 ).list(); 134 // SELECT * from MESSAGE 135 136 //assertEquals(messages.size(), 1); 137 assertEquals(messages.get(0).getText(), "Hello World!"); 138 139 tx.commit(); 140 } 141 142 } finally { 143 TM.rollback(); 144 } 145 } 146 }
3.
1 package org.jpwh.env; 2 3 import org.testng.annotations.AfterSuite; 4 import org.testng.annotations.BeforeSuite; 5 import org.testng.annotations.Optional; 6 import org.testng.annotations.Parameters; 7 8 import java.util.Locale; 9 10 /** 11 * Starts and stops the transaction manager/database pool before/after a test suite. 12 * <p> 13 * All tests in a suite execute with a single {@link TransactionManagerSetup}, call 14 * the static {@link TransactionManagerTest#TM} in your test to access the JTA 15 * transaction manager and database connections. 16 * </p> 17 * <p> 18 * The test parameters <code>database</code> (specifying a supported 19 * {@link DatabaseProduct}) and a <code>connectionURL</code> are optional. 20 * The default is an in-memory H2 database instance, created and destroyed 21 * automatically for each test suite. 22 * </p> 23 */ 24 public class TransactionManagerTest { 25 26 // Static single database connection manager per test suite 27 static public TransactionManagerSetup TM; 28 29 @Parameters({"database", "connectionURL"}) 30 @BeforeSuite() 31 public void beforeSuite(@Optional String database, 32 @Optional String connectionURL) throws Exception { 33 database = "mysql"; 34 TM = new TransactionManagerSetup( 35 database != null 36 ? DatabaseProduct.valueOf(database.toUpperCase(Locale.US)) 37 : DatabaseProduct.H2, 38 connectionURL 39 ); 40 } 41 42 @AfterSuite(alwaysRun = true) 43 public void afterSuite() throws Exception { 44 if (TM != null) 45 TM.stop(); 46 } 47 }
4.
1 package org.jpwh.env; 2 3 import bitronix.tm.TransactionManagerServices; 4 import bitronix.tm.resource.jdbc.PoolingDataSource; 5 6 import javax.naming.Context; 7 import javax.naming.InitialContext; 8 import javax.sql.DataSource; 9 import javax.transaction.Status; 10 import javax.transaction.UserTransaction; 11 import java.util.logging.Logger; 12 13 /** 14 * Provides a database connection pool with the Bitronix JTA transaction 15 * manager (http://docs.codehaus.org/display/BTM/Home). 16 * <p> 17 * Hibernate will look up the datasource and <code>UserTransaction</code> through 18 * JNDI, that's why you also need a <code>jndi.properties</code> file. A minimal 19 * JNDI context is bundled with and started by Bitronix. 20 * </p> 21 */ 22 public class TransactionManagerSetup { 23 24 public static final String DATASOURCE_NAME = "myDS"; 25 26 private static final Logger logger = 27 Logger.getLogger(TransactionManagerSetup.class.getName()); 28 29 protected final Context context = new InitialContext(); 30 protected final PoolingDataSource datasource; 31 public final DatabaseProduct databaseProduct; 32 33 public TransactionManagerSetup(DatabaseProduct databaseProduct) throws Exception { 34 this(databaseProduct, null); 35 } 36 37 public TransactionManagerSetup(DatabaseProduct databaseProduct, 38 String connectionURL) throws Exception { 39 40 logger.fine("Starting database connection pool"); 41 42 logger.fine("Setting stable unique identifier for transaction recovery"); 43 TransactionManagerServices.getConfiguration().setServerId("myServer1234"); 44 45 logger.fine("Disabling JMX binding of manager in unit tests"); 46 TransactionManagerServices.getConfiguration().setDisableJmx(true); 47 48 logger.fine("Disabling transaction logging for unit tests"); 49 TransactionManagerServices.getConfiguration().setJournal("null"); 50 51 logger.fine("Disabling warnings when the database isn't accessed in a transaction"); 52 TransactionManagerServices.getConfiguration().setWarnAboutZeroResourceTransaction(false); 53 54 logger.fine("Creating connection pool"); 55 datasource = new PoolingDataSource(); 56 datasource.setUniqueName(DATASOURCE_NAME); 57 datasource.setMinPoolSize(1); 58 datasource.setMaxPoolSize(5); 59 datasource.setPreparedStatementCacheSize(10); 60 61 // Our locking/versioning tests assume READ COMMITTED transaction 62 // isolation. This is not the default on MySQL InnoDB, so we set 63 // it here explicitly. 64 datasource.setIsolationLevel("READ_COMMITTED"); 65 66 // Hibernate's SQL schema generator calls connection.setAutoCommit(true) 67 // and we use auto-commit mode when the EntityManager is in suspended 68 // mode and not joined with a transaction. 69 datasource.setAllowLocalTransactions(true); 70 71 logger.info("Setting up database connection: " + databaseProduct); 72 this.databaseProduct = databaseProduct; 73 databaseProduct.configuration.configure(datasource, connectionURL); 74 75 logger.fine("Initializing transaction and resource management"); 76 datasource.init(); 77 } 78 79 public Context getNamingContext() { 80 return context; 81 } 82 83 public UserTransaction getUserTransaction() { 84 try { 85 return (UserTransaction) getNamingContext() 86 .lookup("java:comp/UserTransaction"); 87 } catch (Exception ex) { 88 throw new RuntimeException(ex); 89 } 90 } 91 92 public DataSource getDataSource() { 93 try { 94 return (DataSource) getNamingContext().lookup(DATASOURCE_NAME); 95 } catch (Exception ex) { 96 throw new RuntimeException(ex); 97 } 98 } 99 100 public void rollback() { 101 UserTransaction tx = getUserTransaction(); 102 try { 103 if (tx.getStatus() == Status.STATUS_ACTIVE || 104 tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) 105 tx.rollback(); 106 } catch (Exception ex) { 107 System.err.println("Rollback of transaction failed, trace follows!"); 108 ex.printStackTrace(System.err); 109 } 110 } 111 112 public void stop() throws Exception { 113 logger.fine("Stopping database connection pool"); 114 datasource.close(); 115 TransactionManagerServices.getTransactionManager().shutdown(); 116 } 117 118 }
5.
1 package org.jpwh.env; 2 3 import bitronix.tm.resource.jdbc.PoolingDataSource; 4 5 import java.util.Properties; 6 7 public enum DatabaseProduct { 8 9 H2( 10 new DataSourceConfiguration() { 11 @Override 12 public void configure(PoolingDataSource ds, String connectionURL) { 13 ds.setClassName("org.h2.jdbcx.JdbcDataSource"); 14 15 // External instance: jdbc:h2:tcp://localhost/mem:test;USER=sa 16 ds.getDriverProperties().put( 17 "URL", 18 connectionURL != null 19 ? connectionURL : 20 "jdbc:h2:mem:test" 21 ); 22 23 // TODO: http://code.google.com/p/h2database/issues/detail?id=502 24 ds.getDriverProperties().put("user", "sa"); 25 26 // TODO: Don't trace log values larger than X bytes (especially useful for 27 // debugging LOBs, which are accessed in toString()!) 28 // System.setProperty("h2.maxTraceDataLength", "256"); 256 bytes, default is 64 kilobytes 29 } 30 }, 31 org.jpwh.shared.ImprovedH2Dialect.class.getName() 32 ), 33 34 ORACLE( 35 new DataSourceConfiguration() { 36 @Override 37 public void configure(PoolingDataSource ds, String connectionURL) { 38 ds.setClassName("oracle.jdbc.xa.client.OracleXADataSource"); 39 ds.getDriverProperties().put( 40 "URL", 41 connectionURL != null 42 ? connectionURL : 43 "jdbc:oracle:thin:test/test@192.168.56.101:1521:xe" 44 ); 45 46 // Required for reading VARBINARY/LONG RAW columns easily, see 47 // http://stackoverflow.com/questions/10174951 48 Properties connectionProperties = new Properties(); 49 connectionProperties.put("useFetchSizeWithLongColumn", "true"); 50 ds.getDriverProperties().put("connectionProperties", connectionProperties); 51 } 52 }, 53 org.hibernate.dialect.Oracle10gDialect.class.getName() 54 ), 55 56 POSTGRESQL( 57 new DataSourceConfiguration() { 58 @Override 59 public void configure(PoolingDataSource ds, String connectionURL) { 60 ds.setClassName("org.postgresql.xa.PGXADataSource"); 61 if (connectionURL != null) { 62 throw new IllegalArgumentException( 63 "PostgreSQL XADataSource doesn't support connection URLs" 64 ); 65 } 66 ds.getDriverProperties().put("serverName", "10.0.0.2"); 67 ds.getDriverProperties().put("databaseName", "test"); 68 ds.getDriverProperties().put("user", "test"); 69 ds.getDriverProperties().put("password", "test"); 70 } 71 }, 72 org.hibernate.dialect.PostgreSQL82Dialect.class.getName() 73 ), 74 75 MYSQL( 76 new DataSourceConfiguration() { 77 @Override 78 public void configure(PoolingDataSource ds, String connectionURL) { 79 // TODO: MySQL XA support is completely broken, we use the BTM XA wrapper 80 //ds.setClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"); 81 ds.setClassName("bitronix.tm.resource.jdbc.lrc.LrcXADataSource"); 82 ds.getDriverProperties().put( 83 "url", 84 connectionURL != null 85 ? connectionURL : 86 "jdbc:mysql://localhost/test?sessionVariables=sql_mode='PIPES_AS_CONCAT'" 87 ); 88 89 ds.getDriverProperties().put("driverClassName", "com.mysql.jdbc.Driver"); 90 ds.getDriverProperties().put("user", "root"); 91 ds.getDriverProperties().put("password", "1234"); 92 } 93 }, 94 // Yes, this should work with 5.6, no idea why Gail named it 5.7 95 org.hibernate.dialect.MySQL57InnoDBDialect.class.getName() 96 ); 97 98 public DataSourceConfiguration configuration; 99 public String hibernateDialect; 100 101 private DatabaseProduct(DataSourceConfiguration configuration, 102 String hibernateDialect) { 103 this.configuration = configuration; 104 this.hibernateDialect = hibernateDialect; 105 } 106 107 public interface DataSourceConfiguration { 108 109 void configure(PoolingDataSource ds, String connectionURL); 110 } 111 112 }
You can do anything you set your mind to, man!