2016-04-03 3 views
1

Я использую весенний ботинок и шаблон весны jdbc. Я хочу, чтобы экстернализировать SQL-запросы в свойствах или в yml-файле. Я не хочу хранить SQL-запросы в классах java-репозиториев.Как хранить и читать SQL-запросы из свойств или yml-файла в репозитории junbc для загрузки Spring?

Каков наилучший способ справиться с этим случаем?

Так выглядит класс моего репозитория.

@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); 
    } 
+1

Вы когда-нибудь находили хорошее решение для этого? – andre3wap

+0

@ andre3wap Nope. Еще не – ashishjmeshram

+0

Я хочу сделать то же самое. вы нашли какое-нибудь хорошее решение? – Thirumal

ответ

0

Я знаю, что это напрямую не рассматривается, как ваши спрашивать о свойствах файлов или YML, но я расцениваю ваш вопрос вообще как спрашивать о лучшем способе для управления SQL заявления в проекте. Работая над проектами с довольно большим количеством кода SQL, я обнаружил, что MyBatis задерживается без излишней жалобы. В двух словах, он уже обрабатывает экстернализацию sql для внешних xml-файлов и может поддерживать управляемость sql в файлах на хорошем уровне, когда вы накапливаете больше sql.

Чтобы настроить его, вам необходимо настроить компоненты и создать два файла mybatis xml вместе с интерфейсом java для репозитория. Берет пример, вот 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

META-INF/репо/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/репо/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 для настройки компонентов, необходимых для mybatis. Таким образом, для конфигурации вам понадобятся 4 компонента: sqlSessionFactory, 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); 
    } 

В моем прототипе проекте я пошел в базу данных H2 и использую EmbeddedDatabaseBuilder, чтобы заботиться о данных схемы и семян.

META-INF/репо/дб/DDL/создание базы данных,-script.sql:

CREATE TABLE if NOT EXISTS user (
    id INTEGER PRIMARY KEY, 
    name VARCHAR(30) 
); 

META-INF/репо/дб/DML/база данных сеялка-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, вы можете создать новый интерфейс хранилища, его файл сопоставления сопоставителя , свяжите XML-файл mapper с помощью XML-файла sqlmap-config, добавив для него новый элемент <mapper>, а затем добавьте новый репозиторий в виде компонента в конфигурации Spring. Более того, и я не показывал, что это слышно, если userMapper.xml начинает становиться слишком большим и громоздким, вы можете разбить его на более мелкие файлы и по-прежнему поддерживать интерфейс UserRepository.

+0

Я просмотрел его. Кажется, это почти 2,6 года. С тех пор, с тех пор многое изменилось, есть ли лучший способ сделать это сейчас? – ashishjmeshram

0

Я обрабатываюсь следующим образом:

У меня есть @Configuration класса, который создает JdbcTemplate бобов, так что я добавить еще один компонент с классом StringBuilder провести запрос из .sql файла. Вот моя конфигурация:

@Configuration 
public class DBManager { 

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

    @Autowired 
    PropertiesUtils propertiesUtils; 

    @Bean(name = "targetJdbcTemplate") 
    public JdbcTemplate targetJdbcTemplate() throws SQLException { 
     Environment environment = propertiesUtils.getEnvironment(); 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     dataSource.setUrl(environment.getProperty("db.target.url")); 
     dataSource.setUsername(environment.getProperty("db.target.username")); 
     dataSource.setPassword(environment.getProperty("db.target.password")); 

     return new JdbcTemplate(dataSource); 
    } 

    @Bean(name = "targetQueryTemplate") 
    public StringBuilder targetQueryTemplate() { 
     return propertiesUtils.getSQLQueryFromFile(DBDirection.TARGET_DB); 
    } 
} 

PropertiesUtil выглядит следующим образом:

@Configuration 
@PropertySource(value={"classpath:app.properties"}) 
public class PropertiesUtils { 

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

    @Resource 
    private Environment environment; 

    public Environment getEnvironment() { 
     return environment; 
    } 

    /** 
    * to get sql query from .sql file 
    * @param dbDirection which db's query is needed 
    * @return a StringBuilder object which holds needed sql query 
    */ 
    public StringBuilder getSQLQueryFromFile(DBDirection dbDirection) { 
     String filePath = null; 
     StringBuilder sql = null; 
     BufferedReader br = null; 
     InputStreamReader input = null; 
     try { 
      if (dbDirection == DBDirection.SOURCE_DB) 
       filePath = this.environment.getProperty("db.source.query.file"); 
      else if (dbDirection == DBDirection.TARGET_DB){ 
       filePath = this.environment.getProperty("db.target.query.file"); 

      if(filePath == null || filePath.equals("")) { 
       logger.error("filePath cannot be null or empty"); 
       return sql; 
      } 

      InputStream in = PropertiesUtils.class.getClassLoader().getResourceAsStream(filePath); 
      input = new InputStreamReader(in); 
      br = new BufferedReader(input); 
      String str; 
      sql = new StringBuilder(""); 
      while ((str = br.readLine()) != null) { 
       sql.append(str); 
      } 
     } catch (IOException e) { 
      logger.error("Failed to read query from file", e); 
     } finally { 
      try { 
       if(br != null) 
        br.close(); 
       if(input != null) 
        input.close(); 
      } catch (IOException e) { 
       logger.error("Failed to close reader", e); 
      } 
     } 
     return sql; 
    } 
} 

app.properties держит путь .SQL файла. getSQLQueryFromFile читает файл один раз при инициализации контекста.

Затем я подключаю компонентный бит запроса (targetQueryTemplate) к моему репо, это все. Вот мой репо:

@Repository 
public class TargetRepository implements ITargetRepository { 

    private static final Logger logger = LoggerFactory.getLogger(TargetRepository.class); 
    private static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss"; 

    @Autowired 
    @Qualifier("targetJdbcTemplate") 
    private JdbcTemplate targetJdbcTemplate; 

    @Autowired 
    @Qualifier("targetQueryTemplate") 
    private StringBuilder targetQueryTemplate; 

    @Override 
    public void testConnection() { 
     targetJdbcTemplate.execute("select 1 from dual"); 
    } 

    @Override 
    public int[] insert(final ArrayList<Object> list) { 
     return targetJdbcTemplate.batchUpdate(this.targetQueryTemplate.toString(), new BatchPreparedStatementSetter() { 

      @Override 
      public void setValues(PreparedStatement preparedStatement, int i) throws SQLException { 
       // batch adding 
      } 

      @Override 
      public int getBatchSize() { 
       return determineBatchSize(list); 
      } 
     }); 
    } 
} 

Надеюсь, это поможет!

 Смежные вопросы

  • Нет связанных вопросов^_^