JPARepository deleteAllInBatch () не работает должным образом - PullRequest
0 голосов
/ 16 июня 2019

Я пытаюсь удалить некоторые строки из моей таблицы, используя Spring JPA deleteAllInBatch (), но когда количество удаляемых строк превышает некоторое пороговое значение, JPA выдает ошибку.Я не уверен в причине этой ошибки, но нашел билет jira: https://jira.spring.io/browse/DATAJPA-137.

Я не хочу использовать deleteAll (), поскольку он удаляет данные по одному и приводит к проблемам с производительностью.Является ли это недостатком JPA или есть какое-то решение?Я пытался найти обходной путь, но не нашел ничего полезного.Пожалуйста, помогите мне получить эффективное решение для этой операции или некоторые полезные ссылки.Заранее спасибо ...

DbIssueApplication.java

@SpringBootApplication
public class DbIssueApplication 
{
    public static void main(String[] args) 
    {
        ApplicationContext context = SpringApplication.run(DbIssueApplication.class, args);
        TestService service = context.getBean(TestService.class);

        long st = System.currentTimeMillis();

        List<Test> testList = new ArrayList<>();        
        for(int i=0;i<5000;i++)
        {
            testList.add(new Test(i,(i%2==0)?"field1":"field2"));
        }
        service.insert(testList);


        service.deleteByName("field2");

        System.err.println("The processing took = "+(System.currentTimeMillis()-st)+" ms");
    }

}

Test.java

@Entity
@Table(name="test")
public class Test implements Serializable 
{
    private static final long serialVersionUID = -9182756617906316269L;
    @Id
    private Integer id; 
    private String name;

        ... getter,setter and constructors

}

TestRepository.java

public interface TestRepository extends JpaRepository<Test, Integer> 
{
    List<Test> findByName(String name);
}

TestService.java

public interface TestService 
{
    public void insert(List<Test> testList);
    public void deleteByName(String name);
}

TestServiceImpl.java

@Service
public class TestServiceImpl implements TestService 
{
    @Autowired
    TestRepository testRepository;

    @Override
    public void insert(List<Test> testList) 
    {
        testRepository.deleteAllInBatch();
        testRepository.saveAll(testList);
    }

    @Override
    public void deleteByName(String name)
    {
        System.err.println("The number of rows to be deleted = "+testRepository.findByName(name).size());
        testRepository.deleteInBatch(testRepository.findByName(name));
    }


}

dbSchema

create table test
(
    id int,
    name varchar(40)
);

ErrorLog

[           main] o.h.e.t.i.TransactionImpl                : begin
[           main] o.h.h.i.a.QueryTranslatorImpl            : parse() - HQL: delete from com.example.demo.entity.Test x where x = ?1 or x = ?2 or x = ?3 or x = ?4 or ...  x = ?2500
[           main] o.h.h.i.a.ErrorTracker                   : throwQueryException() : no errors
[           main] o.h.e.t.i.TransactionImpl                : rolling back
[      Thread-14] o.h.i.SessionFactoryImpl                 : HHH000031: Closing
[      Thread-14] o.h.t.s.TypeConfiguration$Scope          : Un-scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$Scope@6cf001] from SessionFactory [org.hibernate.internal.SessionFactoryImpl@1ad3d8a]
[      Thread-14] o.h.s.i.AbstractServiceRegistryImpl      : Implicitly destroying ServiceRegistry on de-registration of all child ServiceRegistries
[      Thread-14] o.h.b.r.i.BootstrapServiceRegistryImpl   : Implicitly destroying Boot-strap registry on de-registration of all child ServiceRegistries

=======================================================================================================================================================================================================================================================================================================

[           main] o.h.h.i.QueryTranslatorFactoryInitiator  : QueryTranslatorFactory : org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory@5e167a
[           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
[           main] o.h.h.i.a.QueryTranslatorImpl            : parse() - HQL: select generatedAlias0 from com.example.demo.entity.Test as generatedAlias0 where generatedAlias0.name=:param0
[           main] o.h.h.i.a.ErrorTracker                   : throwQueryException() : no errors
[           main] o.h.h.i.a.QueryTranslatorImpl            : --- HQL AST ---
 \-[QUERY] Node: 'query'
    +-[SELECT_FROM] Node: 'SELECT_FROM'
    |  +-[FROM] Node: 'from'
    |  |  \-[RANGE] Node: 'RANGE'
    |  |     +-[DOT] Node: '.'
    |  |     |  +-[DOT] Node: '.'
    |  |     |  |  +-[DOT] Node: '.'
    |  |     |  |  |  +-[DOT] Node: '.'
    |  |     |  |  |  |  +-[IDENT] Node: 'com'
    |  |     |  |  |  |  \-[IDENT] Node: 'example'
    |  |     |  |  |  \-[IDENT] Node: 'demo'
    |  |     |  |  \-[IDENT] Node: 'entity'
    |  |     |  \-[IDENT] Node: 'Test'
    |  |     \-[ALIAS] Node: 'generatedAlias0'
    |  \-[SELECT] Node: 'select'
    |     \-[IDENT] Node: 'generatedAlias0'
    \-[WHERE] Node: 'where'
       \-[EQ] Node: '='
          +-[DOT] Node: '.'
          |  +-[IDENT] Node: 'generatedAlias0'
          |  \-[IDENT] Node: 'name'
          \-[COLON] Node: ':'
             \-[IDENT] Node: 'param0'

[           main] o.h.h.i.a.HqlSqlBaseWalker               : select << begin [level=1, statement=select]
[           main] o.h.h.i.a.t.FromElement                  : FromClause{level=1} : com.example.demo.entity.Test (generatedAlias0) -> test0_
[           main] o.h.h.i.a.t.FromReferenceNode            : Resolved : generatedAlias0 -> test0_.id
[           main] o.h.h.i.a.t.FromReferenceNode            : Resolved : generatedAlias0 -> test0_.id
[           main] o.h.h.i.a.t.DotNode                      : getDataType() : name -> org.hibernate.type.StringType@d003cd
[           main] o.h.h.i.a.t.FromReferenceNode            : Resolved : generatedAlias0.name -> test0_.name
[           main] o.h.h.i.a.HqlSqlBaseWalker               : select : finishing up [level=1, statement=select]
[           main] o.h.h.i.a.HqlSqlWalker                   : processQuery() :  ( SELECT ( {select clause} test0_.id ) ( FromClause{level=1} test test0_ ) ( where ( = ( test0_.name test0_.id name ) ? ) ) )
[           main] o.h.h.i.a.u.JoinProcessor                : Using FROM fragment [test test0_]
[           main] o.h.h.i.a.HqlSqlBaseWalker               : select >> end [level=1, statement=select]
[           main] o.h.h.i.a.QueryTranslatorImpl            : --- SQL AST ---
 \-[SELECT] QueryNode: 'SELECT'  querySpaces (test)
    +-[SELECT_CLAUSE] SelectClause: '{select clause}'
    |  +-[ALIAS_REF] IdentNode: 'test0_.id as id1_0_' {alias=generatedAlias0, className=com.example.demo.entity.Test, tableAlias=test0_}
    |  \-[SQL_TOKEN] SqlFragment: 'test0_.name as name2_0_'
    +-[FROM] FromClause: 'from' FromClause{level=1, fromElementCounter=1, fromElements=1, fromElementByClassAlias=[generatedAlias0], fromElementByTableAlias=[test0_], fromElementsByPath=[], collectionJoinFromElementsByPath=[], impliedElements=[]}
    |  \-[FROM_FRAGMENT] FromElement: 'test test0_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=generatedAlias0,role=null,tableName=test,tableAlias=test0_,origin=null,columns={,className=com.example.demo.entity.Test}}
    \-[WHERE] SqlNode: 'where'
       \-[EQ] BinaryLogicOperatorNode: '='
          +-[DOT] DotNode: 'test0_.name' {propertyName=name,dereferenceType=PRIMITIVE,getPropertyPath=name,path=generatedAlias0.name,tableAlias=test0_,className=com.example.demo.entity.Test,classAlias=generatedAlias0}
          |  +-[ALIAS_REF] IdentNode: 'test0_.id' {alias=generatedAlias0, className=com.example.demo.entity.Test, tableAlias=test0_}
          |  \-[IDENT] IdentNode: 'name' {originalText=name}
          \-[NAMED_PARAM] ParameterNode: '?' {name=param0, expectedType=org.hibernate.type.StringType@d003cd}

[           main] o.h.h.i.a.ErrorTracker                   : throwQueryException() : no errors
[           main] o.h.h.i.a.QueryTranslatorImpl            : HQL: select generatedAlias0 from com.example.demo.entity.Test as generatedAlias0 where generatedAlias0.name=:param0
[           main] o.h.h.i.a.QueryTranslatorImpl            : SQL: select test0_.id as id1_0_, test0_.name as name2_0_ from test test0_ where test0_.name=?
[           main] o.h.h.i.a.ErrorTracker                   : throwQueryException() : no errors
[           main] o.h.h.i.a.QueryTranslatorImpl            : parse() - HQL: delete from com.example.demo.entity.Test x where x = ?1 or x = ?2 ... or x = ?2500
[           main] o.h.h.i.a.ErrorTracker                   : throwQueryException() : no errors


Пример кода загружен в githubссылка на которую: https://github.com/Anand450623/Stackoverflow

1 Ответ

0 голосов
/ 16 июня 2019

Вы можете попробовать использовать JPQL-запрос для удаления deleteAll() в пакетном режиме, а не по одному.

Тем не менее, вы можете полностью отказаться от orm-framework.Обычный опыт состоит в том, что, хотя вначале это выглядит как хорошая идея, почти оно сталкивается с такими проблемами, как тот, который вы задали здесь: / вы можете прочитать https://www.toptal.com/java/how-hibernate-ruined-my-career Суть этого в том, что отладку труднов любом случае, вы не можете избежать написания собственного SQL в большинстве случаев, JPQL ограничивает вашу выразительность, и он чрезвычайно агрессивен в том, как вы моделируете (например, вы не можете сделать неизменность во многих случаях).

Spring имеетпревосходный шаблон JdbcTemplate, но имейте в виду, что у него есть и недостатки, в основном то, что вы должны сами писать отображение - это говорит о том, что кода не так уж много.Тем не менее, преимущества огромны.Так что, если JPQL-запрос не работает, подумайте, правильно ли использовать JPA (hibernate?) Для начала с

...