Announcement Announcement Module
Collapse
No announcement yet.
??? Large Objects may not be used in auto-commit mode Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • ??? Large Objects may not be used in auto-commit mode

    Hi,

    I'm using spring 1.2.1, hibernate 3.x and postgres 8.x.
    I've problem when trying to retrieve an instance of a class containing a java.sql.Blob field.
    I've tested outside spring (using Hibernate SessionFactory), it works fine and the content of my Blob is correct.

    From within spring, i'm getting the following postgres exception:

    Code:
    org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.
    	at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:172)
    	at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:158)
    	at org.postgresql.jdbc2.AbstractJdbc2Blob.<init>&#40;AbstractJdbc2Blob.java&#58;26&#41;
    	at org.postgresql.jdbc3.AbstractJdbc3Blob.<init>&#40;AbstractJdbc3Blob.java&#58;20&#41;
    	at org.postgresql.jdbc3.Jdbc3Blob.<init>&#40;Jdbc3Blob.java&#58;20&#41;
    	at org.postgresql.jdbc3.Jdbc3ResultSet.getBlob&#40;Jdbc3ResultSet.java&#58;54&#41;
    	at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getBlob&#40;AbstractJdbc2ResultSet.java&#58;312&#41;
    	at org.hibernate.type.BlobType.get&#40;BlobType.java&#58;56&#41;
    	at org.hibernate.type.BlobType.nullSafeGet&#40;BlobType.java&#58;110&#41;
    	at org.hibernate.type.AbstractType.hydrate&#40;AbstractType.java&#58;80&#41;
    	at org.hibernate.persister.entity.BasicEntityPersister.hydrate&#40;BasicEntityPersister.java&#58;1699&#41;
    	at org.hibernate.loader.Loader.loadFromResultSet&#40;Loader.java&#58;925&#41;
    	at org.hibernate.loader.Loader.instanceNotYetLoaded&#40;Loader.java&#58;876&#41;
    	at org.hibernate.loader.Loader.getRow&#40;Loader.java&#58;789&#41;
    	at org.hibernate.loader.Loader.getRowFromResultSet&#40;Loader.java&#58;295&#41;
    	at org.hibernate.loader.Loader.doQuery&#40;Loader.java&#58;389&#41;
    	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections&#40;Loader.java&#58;208&#41;
    	at org.hibernate.loader.Loader.loadEntity&#40;Loader.java&#58;1278&#41;
    I've tried to configure my spring SessionFactory in order to set autocommit to false, but it didn't change a thing.

    Code:
    	<!-- Hibernate SessionFactory -->
    	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="dataSource"><ref local="dataSource"/></property>
    		<property name="mappingResources">
    			<value>com/core/model/model.hbm.xml</value>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">$&#123;hibernate.dialect&#125;</prop>
    				<prop key="hibernate.show_sql">$&#123;hibernate.show_sql&#125;</prop>
    				<prop key="hibernate.connection.release_mode">on_close</prop> 
    				<prop key="hibernate.connection.autocommit">false</prop>
    			</props>
    		</property>
    	</bean>
    Any idea?
    Thanks in advance.

    Michaël.

  • #2
    It says exactly what it is: in PostgreSQL, you have to put your blob-access code inside a transaction. This is RDBMS specific requirement, has nothing to do with Spring nor Hibernate.

    Comment


    • #3
      For future PostgreSQL problems do a quick search on HB forums - it worked for me every time.

      Comment


      • #4
        I've installed & configured a mySQL server...everything runs ok!

        It seems that spring set the auto-commit to false, whatever the configuration you use...

        hum...strange, isn't it?

        Comment


        • #5
          It seems that spring set the auto-commit to false, whatever the configuration you use...
          1. I think that you can configure this aspect.
          2. If it's unconfigurable then for sure there is a good reason for it.

          Comment


          • #6
            lazy loading LOB access on web controller invoked by POST parameter

            I've got a problem that matches this thread:

            Spring 3.0.5
            postgreSQL 8.4
            hibernate 3.x

            I want to use that nice RESTful web controller mechanism with a POST request writing into a @Lob @Basic property in an entity object in a Map<String, DocumentContent>.
            Because postgreSQL-driver wants me to open a transaction when loading LOB map contents sending POST data (languageContents['1'].)content['content'].content=sth produces the following exception:
            Code:
            org.springframework.beans.InvalidPropertyException: Invalid property 'languageContents[1].contents[content]' of bean class [de.algorythm.cmf.model.entity.Document]: Illegal attempt to get property 'contents' threw exception; nested exception is org.hibernate.exception.GenericJDBCException: could not initialize a collection: [de.algorythm.cmf.model.entity.DocumentLanguageContent.contents#1]
            	at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:827)
            ...
            Caused by: org.hibernate.exception.GenericJDBCException: could not initialize a collection: [de.algorythm.cmf.model.entity.DocumentLanguageContent.contents#1]
            	at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)
            ...
            Caused by: org.postgresql.util.PSQLException: LargeObjects (LOB) dürfen im Modus 'auto-commit' nicht verwendet werden.
            	at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:200)
            	at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:172)
            	at org.postgresql.jdbc2.AbstractJdbc2BlobClob.<init>(AbstractJdbc2BlobClob.java:47)
            	at org.postgresql.jdbc2.AbstractJdbc2Clob.<init>(AbstractJdbc2Clob.java:25)
            	at org.postgresql.jdbc3.AbstractJdbc3Clob.<init>(AbstractJdbc3Clob.java:20)
            	at org.postgresql.jdbc3.Jdbc3Clob.<init>(Jdbc3Clob.java:18)
            	at org.postgresql.jdbc3.Jdbc3ResultSet.getClob(Jdbc3ResultSet.java:43)
            	at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getClob(AbstractJdbc2ResultSet.java:384)
            	at org.apache.commons.dbcp.DelegatingResultSet.getClob(DelegatingResultSet.java:568)
            	at org.apache.commons.dbcp.DelegatingResultSet.getClob(DelegatingResultSet.java:568)
            	at org.hibernate.type.descriptor.sql.ClobTypeDescriptor$2.doExtract(ClobTypeDescriptor.java:70)
            	at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:64)
            	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253)
            	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:249)
            	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:229)
            	at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:330)
            	at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2265)
            	at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1527)
            	at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1455)
            	at org.hibernate.loader.Loader.getRow(Loader.java:1355)
            	at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:611)
            	at org.hibernate.loader.Loader.doQuery(Loader.java:829)
            	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
            	at org.hibernate.loader.Loader.loadCollection(Loader.java:2166)
            	... 85 more
            My Entities look as follows:
            Code:
            @Entity
            public class Document {
            
            	@OneToMany(mappedBy="document", targetEntity=DocumentLanguageContent.class, cascade={CascadeType.REMOVE})
            	@MapKey(name="language")
            	private Map<Language, DocumentLanguageContent> languageContents;
            
            	// @id, getter, setter ...
            }
            
            @Entity
            public class DocumentLanguageContent {
            
            	@OneToMany(cascade={CascadeType.REMOVE})
            	@MapKey(name="name")
            	private Map<String, DocumentContent> contents;
            
            	// @id, getter, setter ...
            }
            
            @Entity
            public class DocumentContent {
            
            	@Lob
            	@Basic
            	private String content;
            	@Version
            	private int version;
            
            	// @id, getter, setter ...
            }
            The Controller:
            Code:
            @RequestMapping("/system/{type}")
            @Controller
            public class CrudController {
            
            	@RequestMapping(method = RequestMethod.POST)
            	@Transactional
            	public String edit(@PathVariable("type") final String type,
            			@ModelAttribute("command") @Valid Object entity, 
            			BindingResult result, Model model,
            			HttpServletRequest req)
            			throws Exception {
            		//...
            	}
            	// ...
            }
            My OR-Mapper config in applicationContext.xml:
            Code:
            <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
                    <property name="driverClassName" value="${database.driverClassName}"/>
                    <property name="url" value="${database.url}"/>
                    <property name="username" value="${database.username}"/>
                    <property name="password" value="${database.password}"/>
                </bean>
            	<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
            		<property name="entityManagerFactory" ref="entityManagerFactory"/>
            	</bean>
            	<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
            		<property name="dataSource" ref="dataSource"/>
            	</bean>
                <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
            I know that probably this is not the most performant way but I am implementing an annotation-driven form generator. Reference types in backend form entities that have no backend defined by configuration are part of parent entity's form.
            Simply, the target is to get a form generated for every wanted entity at any cost which can be modified later.
            Needless to say: this is academic.

            To solve this problem I could open a transaction and read the map without problems but the map is read by the spring framework right before my controller method is called with the command so that I cannot open a transaction.
            Probably, I haven't understand the spring concept but sending map values as URL parameter is supported so I am assuming this use case should also work?!

            Edit: Of course, I could and should CRUD referenced entities in an extra controller. Hibernate validator can guarantee back references are not nullable.
            But this would result in having problems with forms and sub forms with different actions.
            BUT if I have an embeddable object referenced at such entity I cannot CRUD it directly with a controller. The @Version field is the only reason why DocumentContent is an entity in this case. Else it would be annotated with @Embeddable. If we have this case we are stuck on the described problem!

            Is there any way to solve this problem? Help, please!!!

            regards,
            Max
            Last edited by MaxMan; Apr 17th, 2011, 07:53 AM. Reason: @Embeddable

            Comment


            • #7
              Help, please

              * push *

              Help, please!

              Comment


              • #8
                Originally posted by MaxMan View Post
                * push *

                Help, please!
                Not sure it helps...

                But, where are you scanning your controller?
                In spring-mvc configuration file or in Spring configuration file ?

                If in spring-mvc configuration file, i'm not sure @Transactional is correctly handled.

                Comment


                • #9
                  The controller is defined by annotation. @Transactional works. But annotating a controller method with @Transactional doesn't help because the exception is thrown when lazy loading the map when spring wants to write URL parameters to command. After spring would have done this my controller method is called. So I want to know if there is some tricky configuration issue or else to make spring assign that url values in a transaction or open a transaction when lazy loading associations.

                  So far I understand: If this problem cannot be solved one would not be able to save @LOB annotated properties in @Embeddable elements by URL parameter with postgreSQL driver without loading the specific properties in a transaction in a @ModelAttribute annotated method.

                  regards,
                  Max
                  Last edited by MaxMan; Apr 18th, 2011, 11:49 AM.

                  Comment


                  • #10
                    You may take a look at "OpenSessionInViewFilter" (I know it exist, I never use it)

                    Comment


                    • #11
                      Solved

                      Finally, I got a nice working solution after having a more detailed look on the stack trace. Saves everything in a transaction:
                      Code:
                      	@Autowired
                      	private ConversionService conversionService;
                      	@Autowired  
                      	private Validator validator;
                      
                      	...
                      
                      	@RequestMapping(method = RequestMethod.POST)
                      	@Transactional
                      	public String edit(@PathVariable("type") final String type,
                      			Model model, HttpServletRequest req)
                      			throws Exception {
                      		// retrieve command object
                      		Object entity = getCommand(type, req);
                      		// validate and bind request data, manually
                      		ServletRequestDataBinder binder = new ServletRequestDataBinder(entity);
                      		binder.setConversionService(conversionService);
                      		binder.setValidator(validator);
                      		binder.bind(req);
                      		binder.validate();
                      		BindingResult result = binder.getBindingResult();
                      		if (model!=null)
                      			// publish BindingResult in model
                      			model.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, result);
                      		// do save entity or display error
                      		Long id = getId(entity);
                      		if (result.hasErrors()) { // validation failed
                      			prepareModel(model, type, type + (id==null ? ".create" : ".update"), entity);
                      			return getViewName(type, "edit");
                      		}
                      		// save entity
                      		if (id==null)
                      			facade.create(entity);
                      		else
                      			facade.edit(entity);
                      		return "redirect:/system/" + type + "/"
                      				+ encodeUrlPathSegment(getId(entity).toString(), req)
                      				+ "/edit";
                      	}
                      
                      	...
                      Last edited by MaxMan; May 10th, 2011, 06:10 PM.

                      Comment

                      Working...
                      X