Java Spring JPA Hibernate:慢速选择查询

Java Spring JPA Hibernate:慢速选择查询,java,spring,oracle,hibernate,jpa,Java,Spring,Oracle,Hibernate,Jpa,我遇到了一个优化问题,我不明白为什么我的查询这么慢 这里是我的实体: @Entity @Table(name = "CLIENT") public class Client { private static final long serialVersionUID = 1L; @Id @Column(name = "CLIENT_ID") @SequenceGenerator(name = "ID_GENERATOR", sequenceName = "CLIENT_S", allocation

我遇到了一个优化问题,我不明白为什么我的查询这么慢

这里是我的实体:

@Entity
@Table(name = "CLIENT")
public class Client {

private static final long serialVersionUID = 1L;
@Id
@Column(name = "CLIENT_ID")
@SequenceGenerator(name = "ID_GENERATOR", sequenceName = "CLIENT_S", allocationSize = 1, initialValue = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ID_GENERATOR")
private Long id;

@Column(name="LOGIN")
private String login;

@Column(name="PASSWORD")
private String password;
那刀呢

@NoRepositoryBean
public interface ClientDao extends JpaRepository<Client, Long>, JpaSpecificationExecutor<Client> {
    Client findByPasswordAndLogin(@Param("login") String customerLogin,@Param("password") String customerHashedPassword);
}
在我们的开发环境中,我们有4000个客户。产量超过一百万

以下是上下文:

  • JDK 8
  • Spring 4.1.6.RELEASE+JPA+Hibernate
  • Oracle数据库10

有什么想法吗?

我已经测试了不同类型的DAO(我不在这里发布代码,因为它太脏了):

  • 使用Hibernate时:~200ms
  • 使用(注入)Spring JDBCTemplate和行映射器:~70毫秒
  • 使用Java语句:~2毫秒
  • 使用Java OracleStatement:~5毫秒
  • 使用Java PreparedStatement:~100ms
  • 使用Java PreparedStatement,并使用Fetch size=5000进行调整:~50ms
  • 使用Java OraclePreparedStatement:~100ms
  • 使用Java OraclePreparedStatement,并使用预取大小调整
注:

  • 由Spring注入的DAO而不是新的ClientDao():+30ms丢失(-sick-)
  • 连接到数据库的时间:46毫秒
我可以使用:

  • 带有手动清理字段的Java语句
  • 应用程序启动时的预连接
  • 不要使用弹簧注射
但是:

  • 不太安全
  • 对于少量行,速度很快;对于大量行,将结果集映射到实体的速度很慢(我也有这个用例)
所以:

带有行映射器的Spring JDBCTemplate似乎是在特定情况下提高性能的最佳解决方案。 我们可以在SQL查询上保持安全性。 但需要编写特定的行映射器来将结果集转换为实体

SpringJDBCTemplate示例

@Repository
public class ClientJdbcTemplateDao {


    private final Logger logger = LoggerFactory.getLogger(ClientJdbcTemplateDao.class);

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public List<Client> find() {
        List<Client> c = this.jdbcTemplate.query( "SELECT login FROM Client WHERE LOGIN='xxxx' AND PASSWORD='xxx'", new ClientRowMapper());
        return c;
    }
}
@存储库
公共类ClientJdbcTemplateDao{
私有最终记录器Logger=LoggerFactory.getLogger(ClientJdbcTemplateDao.class);
私有JdbcTemplate JdbcTemplate;
@自动连线
public void setDataSource(数据源数据源){
this.jdbcTemplate=新的jdbcTemplate(数据源);
}
公共列表查找(){
List c=this.jdbcTemplate.query(“选择从客户端登录,其中login='xxxx'和PASSWORD='xxx'”,new ClientRowMapper());
返回c;
}
}
客户端行映射器示例

public class ClientRowMapper implements RowMapper<Client> {

    @Override
    public Client mapRow(ResultSet arg0, int arg1) throws SQLException {
        // HERE IMPLEMENTS THE CONVERTER
        // Sample : 
        // String login = arg0.getString("LOGIN")
        // Client client = new Client(login);
        // return client;
    }
}
公共类ClientRowMapper实现了RowMapper{
@凌驾
公共客户端映射行(结果集arg0,int arg1)引发SQLException{
//这里实现了转换器
//样本:
//String login=arg0.getString(“登录”)
//客户端=新客户端(登录);
//返回客户;
}
}

可能更好,欢迎任何建议。

我已经测试了不同类型的DAO(我不在这里发布代码,因为它太脏了):

  • 使用Hibernate时:~200ms
  • 使用(注入)Spring JDBCTemplate和行映射器:~70毫秒
  • 使用Java语句:~2毫秒
  • 使用Java OracleStatement:~5毫秒
  • 使用Java PreparedStatement:~100ms
  • 使用Java PreparedStatement,并使用Fetch size=5000进行调整:~50ms
  • 使用Java OraclePreparedStatement:~100ms
  • 使用Java OraclePreparedStatement,并使用预取大小调整
注:

  • 由Spring注入的DAO而不是新的ClientDao():+30ms丢失(-sick-)
  • 连接到数据库的时间:46毫秒
我可以使用:

  • 带有手动清理字段的Java语句
  • 应用程序启动时的预连接
  • 不要使用弹簧注射
但是:

  • 不太安全
  • 对于少量行,速度很快;对于大量行,将结果集映射到实体的速度很慢(我也有这个用例)
所以:

带有行映射器的Spring JDBCTemplate似乎是在特定情况下提高性能的最佳解决方案。 我们可以在SQL查询上保持安全性。 但需要编写特定的行映射器来将结果集转换为实体

SpringJDBCTemplate示例

@Repository
public class ClientJdbcTemplateDao {


    private final Logger logger = LoggerFactory.getLogger(ClientJdbcTemplateDao.class);

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public List<Client> find() {
        List<Client> c = this.jdbcTemplate.query( "SELECT login FROM Client WHERE LOGIN='xxxx' AND PASSWORD='xxx'", new ClientRowMapper());
        return c;
    }
}
@存储库
公共类ClientJdbcTemplateDao{
私有最终记录器Logger=LoggerFactory.getLogger(ClientJdbcTemplateDao.class);
私有JdbcTemplate JdbcTemplate;
@自动连线
public void setDataSource(数据源数据源){
this.jdbcTemplate=新的jdbcTemplate(数据源);
}
公共列表查找(){
List c=this.jdbcTemplate.query(“选择从客户端登录,其中login='xxxx'和PASSWORD='xxx'”,new ClientRowMapper());
返回c;
}
}
客户端行映射器示例

public class ClientRowMapper implements RowMapper<Client> {

    @Override
    public Client mapRow(ResultSet arg0, int arg1) throws SQLException {
        // HERE IMPLEMENTS THE CONVERTER
        // Sample : 
        // String login = arg0.getString("LOGIN")
        // Client client = new Client(login);
        // return client;
    }
}
公共类ClientRowMapper实现了RowMapper{
@凌驾
公共客户端映射行(结果集arg0,int arg1)引发SQLException{
//这里实现了转换器
//样本:
//String login=arg0.getString(“登录”)
//客户端=新客户端(登录);
//返回客户;
}
}

也许可以更好,欢迎任何建议。

什么是可自定义审核的
?创建一个
客户机
实例是否很昂贵?您是否尝试过在应用程序端测量事务执行时间?是否可以发布hibernate生成的实际sql?您可能正在运行一些加载或其他后续查询。Hibernate统计信息还可以告诉您实际的查询执行时间。我已经用Hibernate查询更新了post,并删除了CustomAuditable(在本文中没有用,我不想详细说明如何避免post过载-结果是一样的)。为什么我要在应用方面采取措施?它在D上走得很慢