답변:
먼저 준비된 명령문에서 쿼리 매개 변수 사용을 고려하십시오.
PreparedStatement stm = c.prepareStatement("UPDATE user_table SET name=? WHERE id=?");
stm.setString(1, "the name");
stm.setInt(2, 345);
stm.executeUpdate();
수행 할 수있는 다른 작업은 모든 쿼리를 속성 파일에 보관하는 것입니다. 예를 들어 query.properties 파일에서 위의 쿼리를 배치 할 수 있습니다.
update_query=UPDATE user_table SET name=? WHERE id=?
그런 다음 간단한 유틸리티 클래스의 도움으로 :
public class Queries {
private static final String propFileName = "queries.properties";
private static Properties props;
public static Properties getQueries() throws SQLException {
InputStream is =
Queries.class.getResourceAsStream("/" + propFileName);
if (is == null){
throw new SQLException("Unable to load property file: " + propFileName);
}
//singleton
if(props == null){
props = new Properties();
try {
props.load(is);
} catch (IOException e) {
throw new SQLException("Unable to load property file: " + propFileName + "\n" + e.getMessage());
}
}
return props;
}
public static String getQuery(String query) throws SQLException{
return getQueries().getProperty(query);
}
}
다음과 같이 쿼리를 사용할 수 있습니다.
PreparedStatement stm = c.prepareStatement(Queries.getQuery("update_query"));
이것은 다소 간단한 해결책이지만 잘 작동합니다.
InputStream내부에 넣는 것이 좋습니다 if (props == null).
임의의 SQL의 경우 jOOQ를 사용 하십시오 . jOOQ 현재 지원 SELECT, INSERT, UPDATE, DELETE, TRUNCATE,와 MERGE. 다음과 같이 SQL을 생성 할 수 있습니다.
String sql1 = DSL.using(SQLDialect.MYSQL)
.select(A, B, C)
.from(MY_TABLE)
.where(A.equal(5))
.and(B.greaterThan(8))
.getSQL();
String sql2 = DSL.using(SQLDialect.MYSQL)
.insertInto(MY_TABLE)
.values(A, 1)
.values(B, 2)
.getSQL();
String sql3 = DSL.using(SQLDialect.MYSQL)
.update(MY_TABLE)
.set(A, 1)
.set(B, 2)
.where(C.greaterThan(5))
.getSQL();
SQL 문자열을 얻는 대신 jOOQ를 사용하여 실행할 수도 있습니다. 보다
(면책 조항 : 나는 jOOQ 뒤에있는 회사에서 일합니다)
"?"할지 또는 바인딩 값을 인라인할지 여부를 선택할 수 있습니다.
고려해야 할 한 가지 기술은 SQLJ 입니다. 즉, Java에 SQL 문을 직접 포함하는 방법입니다. 간단한 예로 TestQueries.sqlj라는 파일에 다음이있을 수 있습니다.
public class TestQueries
{
public String getUsername(int id)
{
String username;
#sql
{
select username into :username
from users
where pkey = :id
};
return username;
}
}
.sqlj 파일을 가져와 순수 Java로 변환하는 추가 사전 컴파일 단계가 있습니다. 즉, 다음으로 구분 된 특수 블록을 찾습니다.
#sql
{
...
}
JDBC 호출로 변환합니다. SQLJ를 사용하면 몇 가지 주요 이점이 있습니다.
대부분의 주요 데이터베이스 공급 업체를위한 변환기 구현이 있으므로 필요한 모든 것을 쉽게 찾을 수 있습니다.
나는 Spring JDBC를 살펴볼 것이다 . 프로그래밍 방식으로 SQL을 실행해야 할 때마다 사용합니다. 예:
int countOfActorsNamedJoe
= jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});
모든 종류의 SQL 실행, 특히 쿼리에 정말 좋습니다. 전체 ORM의 복잡성을 추가하지 않고도 결과 집합을 개체에 매핑하는 데 도움이됩니다.
저는 Spring의 명명 된 JDBC 매개 변수를 사용하는 경향이 있으므로 "select * from blah where colX = ': someValue'"와 같은 표준 문자열을 작성할 수 있습니다. 꽤 읽기 쉬운 것 같아요.
대안은 별도의 .sql 파일에 문자열을 제공하고 유틸리티 메서드를 사용하여 내용을 읽는 것입니다.
오, Squill도 살펴볼 가치가 있습니다 : https://squill.dev.java.net/docs/tutorial.html
Hibernate와 같은 ORM 사용에 대한 권장 사항을 두 번째로 설명합니다. 그러나 확실히 작동하지 않는 상황이 있기 때문에이 기회를 통해 내가 작성하는 데 도움이 된 몇 가지 내용을 소개 하겠습니다 . SqlBuilder 는 "빌더"스타일을 사용하여 SQL 문을 동적으로 빌드하기위한 자바 라이브러리입니다. 상당히 강력하고 유연합니다.
저는 임시보고 목적을 위해 매우 동적 인 SQL 문을 구성해야하는 Java 서블릿 애플리케이션을 개발하고 있습니다. 앱의 기본 기능은 명명 된 HTTP 요청 매개 변수를 사전 코딩 된 쿼리에 제공하고 형식이 잘 지정된 출력 테이블을 생성하는 것입니다. Spring MVC와 의존성 주입 프레임 워크를 사용하여 모든 SQL 쿼리를 XML 파일에 저장하고 테이블 형식화 정보와 함께보고 애플리케이션에로드했습니다. 결국보고 요구 사항은 기존 매개 변수 매핑 프레임 워크의 기능보다 더 복잡 해져서 직접 작성해야했습니다. 이것은 개발 과정에서 흥미로운 작업이었으며 내가 찾을 수있는 다른 어떤 것보다 훨씬 강력한 매개 변수 매핑을위한 프레임 워크를 생성했습니다.
새 매개 변수 매핑은 다음과 같습니다.
select app.name as "App",
${optional(" app.owner as "Owner", "):showOwner}
sv.name as "Server", sum(act.trans_ct) as "Trans"
from activity_records act, servers sv, applications app
where act.server_id = sv.id
and act.app_id = app.id
and sv.id = ${integer(0,50):serverId}
and app.id in ${integerList(50):appId}
group by app.name, ${optional(" app.owner, "):showOwner} sv.name
order by app.name, sv.name
결과 프레임 워크의 장점은 적절한 유형 검사 및 제한 검사를 통해 HTTP 요청 매개 변수를 쿼리로 직접 처리 할 수 있다는 것입니다. 입력 유효성 검사에 추가 매핑이 필요하지 않습니다. 위의 예제 쿼리에서 serverId 라는 매개 변수 가 정수로 캐스트 될 수 있고 0-50 범위에 있는지 확인합니다. 매개 변수 appId 는 길이 제한이 50 인 정수 배열로 처리됩니다. showOwner이 존재하고 "true"로 설정하면 따옴표 안의 SQL 비트가 선택적 필드 매핑에 대해 생성 된 쿼리에 추가됩니다. 필드 추가 매개 변수 매핑이있는 SQL의 선택적 세그먼트를 포함하여 여러 매개 변수 유형 매핑을 사용할 수 있습니다. 개발자가 생각할 수있는 것처럼 복잡한 쿼리 매핑을 허용합니다. 보고서 구성에 주어진 쿼리가 PreparedStatement를 통해 최종 매핑을 가질 것인지 또는 단순히 미리 빌드 된 쿼리로 실행되는지를 결정하는 컨트롤도 있습니다.
샘플 Http 요청 값의 경우 :
showOwner: true
serverId: 20
appId: 1,2,3,5,7,11,13
다음 SQL을 생성합니다.
select app.name as "App",
app.owner as "Owner",
sv.name as "Server", sum(act.trans_ct) as "Trans"
from activity_records act, servers sv, applications app
where act.server_id = sv.id
and act.app_id = app.id
and sv.id = 20
and app.id in (1,2,3,5,7,11,13)
group by app.name, app.owner, sv.name
order by app.name, sv.name
저는 Spring이나 Hibernate 또는 그 프레임 워크 중 하나가 유형을 확인하고 배열 및 기타 이러한 기능과 같은 복잡한 데이터 유형을 허용하는보다 강력한 매핑 메커니즘을 제공해야한다고 생각합니다. 내 목적으로 만 엔진을 작성했지만 일반 릴리스에서는 읽지 못합니다. 현재 Oracle 쿼리에서만 작동하며 모든 코드는 대기업에 속합니다. 언젠가는 내 아이디어를 가지고 새로운 오픈 소스 프레임 워크를 구축 할 수 있지만, 기존의 거물 중 한 명이 도전을 맡길 바랍니다.
MyBatis ( www.mybatis.org )를 살펴볼 수도 있습니다 . Java 코드 외부에서 SQL 문을 작성하는 데 도움이되며 SQL 결과를 Java 객체에 매핑합니다.
Google은 기본적으로 기본 SQLite 데이터베이스에 대한 추상화 계층 인 Android 앱용 SQL 을 작성하는 매우 깔끔한 방법을 제공하는 Room Persitence 라이브러리라는 라이브러리 를 제공합니다 . Bellow는 공식 웹 사이트의 짧은 코드 스 니펫입니다.
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND "
+ "last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
라이브러리의 공식 문서에는 더 많은 예제와 더 나은 문서가 있습니다.
Java ORM 인 MentaBean이라는 것도 있습니다. 그것은 좋은 기능을 가지고 있으며 SQL을 작성하는 매우 간단한 방법 인 것 같습니다.
Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite. 따라서 RDBMS 용 일반 ORM 라이브러리가 아닙니다. 주로 Android 앱용입니다.
XML 파일에서 읽을 수 있습니다. 유지 관리 및 작업이 쉽습니다. 표준 STaX, DOM, SAX 파서는 Java에서 몇 줄의 코드로 만들 수 있습니다.
SQL로 더 많은 작업을 수행하는 데 도움이되도록 태그에 속성이있는 일부 의미 정보를 가질 수 있습니다. 메서드 이름이나 쿼리 유형 또는 코딩을 줄이는 데 도움이되는 모든 것이 될 수 있습니다.
xml을 jar 외부에 넣고 쉽게 유지할 수 있습니다. 특성 파일과 동일한 이점.
XML은 확장 가능하며 다른 형식으로 쉽게 변환 할 수 있습니다.
I don't see a reason to make use of XML. 편집 할 수 없어 이전 댓글을 삭제 했습니다.
여러 줄로 나누는 PreparedStatements의 긴 SQL 문자열 (텍스트 파일에 쉽게 제공하고 리소스로로드 할 수 있음)을 제외하고 문자열 연결을 어떻게 얻습니까?
SQL 문자열을 직접 작성하지 않습니까? 그것은 프로그래밍에서 가장 큰 금지입니다. PreparedStatements를 사용하고 데이터를 매개 변수로 제공하십시오. SQL 주입의 가능성을 크게 줄입니다.