Mybatis Porxy 동적 에이전트 와 sql 해석 교체 문제 분석
개술
Mybatis 에서 자주 사용 하 는 역할 은 데이터베이스 에 있 는 표 의 필드 맵 을 대상 으로 하 는 속성 을 말 하 는 것 입 니 다.Mybatis 에 들 어가 기 전에 원생 JDBC 는 몇 가지 절차 가 있 습 니 다.JDBC 드라이버 패 키 지 를 가 져 오고 DriverManager 를 통 해 구동 을 등록 하고 연결 을 만 들 며 Statement 을 만 들 고 삭제 하고 검사 하 며 결과 집합 을 조작 하고 연결 을 닫 습 니 다.
프로 세 스 상세 설명
먼저 클래스 로 딩 을 진행 하고 DriverManager 를 통 해 구동 을 등록 합 니 다.
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("");
왜 여기에 직접 등록 할 수 있 습 니까?com.my sql.jdbc.Driver 는 Driver.class 에 불 러 옵 니 다.DriverManager 에서 먼저 정적 코드 블록 이 있어 서 드라이버 를 초기 화 합 니 다.
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
loadInitialDrivers()를 통 해 Driver 를 불 러 오고 jdbc.drivers 를 꺼 내 며 ServiceLoader 를 통 해 Driver.class 를 읽 고 driver 와 모든 교체 기 를 읽 으 며 교체 합 니 다.
private static void loadInitialDrivers() {
String drivers;
// , jdbc.drivers
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
// driver
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
//
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
Driver 를 불 러 온 후에 데이터베이스 와 의 연결 connection 을 얻 을 수 있 습 니 다.connection 은 Statement 을 만 들 수 있 습 니 다.Statement 은 sql 문 구 를 실행 할 수 있 습 니 다.결 과 를 결과 집합 으로 되 돌려 주 고 가 져 온 결과 집합 을 List 집합 에 옮 겨 놓 을 수 있 습 니 다.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from mybatis.user");
while (resultSet.next()) {
int id = resultSet.getInt(1);
String username = resultSet.getString(2);
list.add(new User(id,username));
}
원생 JDBC 직접 조작 에 서 는 번 거 로 운 절차 가 업무 코드 에 서 는 사용 되 지 않 으 며,Mybatis 는 더 편리 하 게 사용 할 수 있다.JDK 동적 에이전트
sql 구문 분석 교체
JDK 동적 에이전트 에 서 는 프 록 시 라 는 클래스 를 이용 하여 이 루어 집 니 다.프 록 시 에 서 는 new Proxy Instance()방법 이 있 습 니 다.동적 프 록 시 인 스 턴 스 를 만 듭 니 다.
interface UserMapper {
@Select("select * from mybatis.user where id =#{id}")
List<User> selectUserList();
}
public static void main(String[] args) {
UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(
JDKMybatis.class.getClassLoader(),
new Class<?>[]{UserMapper.class},
new InvocationHandler() {
/**
* invoke() method,args
* @param proxy
* @param method
* @param args
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// ,
Select annotation = method.getAnnotation(Select.class);
if (annotation != null) {
String[] value = annotation.value();
System.out.println(Arrays.toString(value));
}
return null;
}
});
userMapper.selectUserList(1);
}
new Proxy Instance()의 생 성 은 세 개의 인자 가 필요 합 니 다.원본 코드 를 보면 ClassLoader 류 로 더,interfaces 인터페이스(Mapper 인터페이스),InvocationHandler 프로세서 가 필요 하 다 는 것 을 알 수 있 습 니 다.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
sql 문장의 인 자 를 꺼 내 args 에 넣 으 려 면 맵 이 필요 합 니 다.
문제.
반사 획득 방법의 매개 변수 이름,method.getParameters()에서 얻 은 매개 변 수 는 모두 arg 0,arg 1...의미 없 는 매개 변수 입 니 다.
자바 8 이전에 코드 를 클 라 스 파일 로 컴 파일 한 후 방법 매개 변수 유형 은 고정 되 어 있 으 나 매개 변수 이름 은 잃 어 버 렸 습 니 다.컴 파일 할 때 컴 파일 옵션 이 필요 합 니 다.자바 c-parameters 는 기본적으로 닫 혀 있 습 니 다.아이디어 에서 열 려 야 합 니 다.열 린 후에 컴 파일 원본 파일 을 다시 시작 해 야 합 니 다.
이 방식 은 현재 환경 설정 만 임시로 해결 할 수 있 고 다른 사람 이 코드 를 실행 할 때 다시 설정 해 야 합 니 다.
다른 해결 방법 은 pom 파일 에 컴 파일 파 라 메 터 를 추가 합 니 다.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
컴 파일 이 완료 되면 다시 실행 하고 method.getParameters()를 통 해 인 자 를 가 져 옵 니 다.원래 sql 을 분석 하려 면\#{}을 교체 해 야 합 니 다.이 럴 때 StringBuffer 클래스 를 사용 하여 교체 할 수 있 습 니 다.
private static String parseSql(String sql, Map<String, Object> argsNameMap) {
//
char[] str = {'#', '{'};
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < sql.length(); i++) {
char aloneParseSql = sql.charAt(i);
if (str[0] == aloneParseSql) {
int nextIndex = i + 1;
char nextChar = sql.charAt(nextIndex);
// # { ,
if (str[1] != nextChar) {
throw new RuntimeException(String.format(
" :#{
sql:%s
index:%d",
stringBuilder.toString(), nextIndex));
}
/*
1
2 #{}
3 argsName argsValue
4 stringBuilder sql
*/
StringBuilder partStringBuilder = new StringBuilder();
i = partParseSql(partStringBuilder, sql, nextIndex);
String argsName = partStringBuilder.toString();
Object argsValue = argsNameMap.get(argsName);
stringBuilder.append(argsValue.toString());
}
// ,
stringBuilder.append(aloneParseSql);
}
return stringBuilder.toString();
}
그 중에서 교체 할 값 을 StringBuffer 클래스 로 구현 해 야 합 니 다.
private static int partParseSql(StringBuilder partStringBuilder, String sql, int nextIndex) {
// nextIndex { ,
nextIndex++;
char[] str = {'}'};
for (; nextIndex < sql.length(); nextIndex++) {
char indexSql = sql.charAt(nextIndex);
if (str[0] != indexSql) {
partStringBuilder.append(indexSql);
}
if (str[0] == indexSql) {
return nextIndex;
}
}
throw new RuntimeException(String.format(
" :}
index:%d",
nextIndex));
}
invoke 방법 에서 다시 호출 하여 sql 문장의 동적 조합 을 완성 합 니 다.
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// ,
Select annotation = method.getAnnotation(Select.class);
Map<String, Object> argsNameMap = MapBuildArgsName(method, args);
if (annotation != null) {
String[] value = annotation.value();
String sql = value[0];
sql = parseSql(sql, argsNameMap);
System.out.println(sql);
}
return null;
}
Mybatis(1)Porxy 동적 에이전트 와 sql 해석 교체 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 Mybatis(1)Porxy 동적 에이전트 와 sql 해석 교체 내용 은 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 지원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
SpringMVC와 Mybatis 집합은 호출 저장 프로세스, 사무 제어 실례를 실현한다SSM 프레임워크에서 호출 데이터베이스의 저장 프로세스와 사무 제어에 자주 사용되는데 다음은 증빙서류를 저장하는 예를 들어 소개한다. 1. Oracle에 저장된 프로세스 코드는 다음과 같습니다(주요 논리는 증빙 서류...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.