java - 如何在 Spring Boot jdbc 存储库中存储和读取属性或 yml 文件中的 SQL 查询?

标签 java sql spring jdbc properties-file

我正在使用 spring boot 和 spring jdbc 模板。我想在属性或 yml 文件中外部化 SQL 查询。我不想将 SQL 查询存储在 java 存储库类中。

处理这种情况的最佳方法是什么?

这就是我的存储库类现在的样子。

@Repository
public class UserRepositoryImpl extends BaseRepository implements UserRepository {

    @Override
    public List<User> findAll(){
        String sqlQuery = "SELECT * FROM users";
        return jdbcTemplate.query(sqlQuery,  userMapper);
    }

    @Override
    public User findById(Long userId){
        String sqlQuery = "SELECT * FROM users WHERE id = :userId";
        Map<String, String> namedParameters = new HashMap<String, String>();
        namedParameters.put("userId", String.valueOf(userId));
        return jdbcTemplate.queryForObject(sqlQuery, namedParameters, userMapper);
    }

最佳答案

我知道这并不能直接解决您对属性文件或 yml 的询问,但我通常将您的问题解释为询问在项目中管理 sql 语句的最佳方法。在处理过包含大量 SQL 代码的项目后,我发现 MyBatis 能够坚持下去,没有太多提示。简而言之,它已经处理了将 sql 外部化为外部 xml 文件的处理,并且随着您积累更多的 sql,可以将文件中 sql 的可管理性保持在良好的水平。

要设置它,您基本上需要配置 bean 并创建两个 mybatis xml 文件以及存储库的 java 接口(interface)。以您的示例为例,这是用户存储库的 mybatis:

public class User {

  private Long id;
  private String name;

 ...
}

public interface UserRepository {

  List<User> findAll();

  User findById( @Param( "id" ) Long userId );

}

@Param 将 'id' 值映射到 SQL 中的 #{id} 表达式

META-INF/repo/sql/userMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bushcoder.so.app.user.UserRepository">

    <resultMap id="user" type="com.bushcoder.so.app.user.User">
        <id property="id" column="userId"/>
        <result property="name" column="name"/>
    </resultMap>

    <select id="findAll" resultMap="user">
        SELECT id, name FROM user
    </select>

    <select id="findById" parameterType="long" resultMap="user">
        SELECT id, name FROM user WHERE id = #{id}
    </select>

</mapper>

注意:#{id} 将提供通过调用 userRepository.findById 传入的值

META-INF/repo/sql/sqlmap-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//www.mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >
<configuration>

    <mappers>
        <mapper resource="META-INF/repo/sql/userMapper.xml"/>
    </mappers>

</configuration>

'META-INF/repo/sql/sqlmap-config.xml' 路径将在 Java Config 中用于设置 mybatis 所需的 bean。因此,对于配置,您需要 4 个 bean:s​​qlSessionFactory、sqlSessionTemplate、dataSource 和 userRepository。这些需要位于配置类中的某个位置以供 Spring 处理。
  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
    sqlSessionFactory.setDataSource(dataSource());
    sqlSessionFactory.setConfigLocation( new ClassPathResource( "META-INF/repo/sql/sqlmap-config.xml" ) );
    return sqlSessionFactory.getObject();
  }

  @Bean
  public SqlSessionTemplate sqlSessionTemplate() throws Exception {
    return new SqlSessionTemplate(sqlSessionFactory());
  }

  @Bean
  public DataSource dataSource() {
    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    EmbeddedDatabase db = builder
        .setType( EmbeddedDatabaseType.H2)
        .addScript("META-INF/repo/db/ddl/create-database-script.sql")
        .addScript("META-INF/repo/db/dml/database-seeder-script.sql")
        .build();
    return db;
  }

  @Bean
  public UserRepository userRepository() throws Exception {
    return sqlSessionTemplate().getMapper( UserRepository.class );
  }

在我的原型(prototype)项目中,我使用了 H2 数据库并使用 EmbeddedDatabaseBuilder 来处理模式和种子数据。

META-INF/repo/db/ddl/create-database-script.sql:
CREATE TABLE if NOT EXISTS user (
  id    INTEGER PRIMARY KEY,
  name  VARCHAR(30)
);

META-INF/repo/db/dml/database-seeder-script.sql:
INSERT INTO user (id, name) VALUES (1, 'BOB');
INSERT INTO user (id, name) VALUES (2, 'LARRY');
INSERT INTO user (id, name) VALUES (3, 'FRANK');
INSERT INTO user (id, name) VALUES (4, 'CHARLIE');
INSERT INTO user (id, name) VALUES (5, 'GARRY');

您很可能会将存储库连接到服务中。可能看起来像这样:
public interface UserService {

  List<User> findAll();

  User findById(Long userId);

}

@Service
public class UserServiceImpl implements UserService {

  @Inject
  private UserRepository userRepository;

  @Override
  public List<User> findAll() {
    return userRepository.findAll();
  }

  @Override
  public User findById( Long userId ) {
    return userRepository.findById( userId );
  }
}

调用代码可能是这样的:
@SpringBootApplication
@Import ( AppConfig.class )
public class MybatisConfigExampleApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run( MybatisConfigExampleApplication.class, args );

        final UserService users = ( UserService ) context.getBean( "userServiceImpl" );

        final List<User> allUsers = users.findAll();
        System.out.println( "allUsers = " + allUsers );

        final User userById_5 = users.findById( 5L );
        System.out.println( "userById_5 = " + userById_5 );
    }
}

现在,当您开始积累更多 sql 时,您将创建一个新的存储库接口(interface),它的匹配映射器文件,通过 sqlmap-config xml 文件通过添加新的 <mapper> 链接映射器 xml 文件元素,然后将新存储库作为 bean 添加到 Spring 的配置中。此外,如果 userMapper.xml 开始变得太大和笨重,你可以将它分成更小的文件并仍然保留 UserRepository 接口(interface),并且我没有显示它。

关于java - 如何在 Spring Boot jdbc 存储库中存储和读取属性或 yml 文件中的 SQL 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36384221/

相关文章:

java cachedThreadPool 杀死提交的线程

sql - 为什么仅索引扫描需要这么长时间?

mysql - 在MYSQL中获取一个月中的星期几

java - Spring 3.x - 如何从返回数据的映射重定向?

java - 启动JavaFX程序时按钮为 "selected"

java - 为什么我们不能对声明为父类类型且元素包含子类引用的数组使用仅子方法?

java - 部署 WAR 时 Tomcat 7 运行时错误

mysql - sql 查询来检查许多兴趣是否匹配

java - 使用fixedRate调度的Spring 3似乎在某个点后意外停止执行,如何调试?

java - 无法使用 Gradle 添加 Spring 依赖项