MyBatis
实现思路
1.自定义注解
2.通过动态代理的方法来初始化接口并拦截其带有注解的方法
3.拆分注解中的sql,以原生的JDBC的方式执行拼接后的sql
引入Pom文件
< project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns: xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
< modelVersion> 4.0 .0 < / modelVersion>
< groupId> com. cy< / groupId>
< artifactId> my- mybatis< / artifactId>
< version> 0.0 .1 - SNAPSHOT< / version>
< dependencies>
< ! -- mybatis核心包 -- >
< dependency>
< groupId> org. mybatis< / groupId>
< artifactId> mybatis< / artifactId>
< version> 3.4 .5 < / version>
< / dependency>
< ! -- 引入Spring - AOP等相关Jar -- >
< dependency>
< groupId> org. springframework< / groupId>
< artifactId> spring- core< / artifactId>
< version> 3.0 .6 . RELEASE< / version>
< / dependency>
< dependency>
< groupId> org. springframework< / groupId>
< artifactId> spring- context< / artifactId>
< version> 3.0 .6 . RELEASE< / version>
< / dependency>
< dependency>
< groupId> org. springframework< / groupId>
< artifactId> spring- aop< / artifactId>
< version> 3.0 .6 . RELEASE< / version>
< / dependency>
< dependency>
< groupId> org. springframework< / groupId>
< artifactId> spring- orm< / artifactId>
< version> 3.0 .6 . RELEASE< / version>
< / dependency>
< dependency>
< groupId> org. aspectj< / groupId>
< artifactId> aspectjrt< / artifactId>
< version> 1.6 .1 < / version>
< / dependency>
< dependency>
< groupId> aspectj< / groupId>
< artifactId> aspectjweaver< / artifactId>
< version> 1.5 .3 < / version>
< / dependency>
< dependency>
< groupId> cglib< / groupId>
< artifactId> cglib< / artifactId>
< version> 2.1_2 < / version>
< / dependency>
< ! -- https: / / mvnrepository. com/ artifact/ com. mchange/ c3p0 -- >
< dependency>
< groupId> com. mchange< / groupId>
< artifactId> c3p0< / artifactId>
< version> 0.9 .5 .2 < / version>
< / dependency>
< ! -- https: / / mvnrepository. com/ artifact/ mysql/ mysql- connector- java -- >
< dependency>
< groupId> mysql< / groupId>
< artifactId> mysql- connector- java< / artifactId>
< version> 5.1 .37 < / version>
< / dependency>
< ! -- https: / / mvnrepository. com/ artifact/ asm/ asm -- >
< dependency>
< groupId> asm< / groupId>
< artifactId> asm< / artifactId>
< version> 3.3 .1 < / version>
< / dependency>
< / dependencies>
< / project>
导入SQL文件
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0 ;
DROP TABLE IF EXISTS ` t_users` ;
CREATE TABLE ` t_users` (
` name` varchar ( 255 ) DEFAULT NULL ,
` id` int ( 11 ) NOT NULL AUTO_INCREMENT ,
` age` int ( 11 ) DEFAULT NULL ,
PRIMARY KEY ( ` id` )
) ENGINE = InnoDB AUTO_INCREMENT = 30 DEFAULT CHARSET = utf8;
BEGIN ;
INSERT INTO ` t_users` VALUES ( 'test001' , 28 , 20 ) ;
INSERT INTO ` t_users` VALUES ( 'test002' , 29 , 21 ) ;
COMMIT ;
SET FOREIGN_KEY_CHECKS = 1 ;
创建实体类
public class User {
private Integer id;
private String userName;
private Integer userAge;
public String getUserName ( ) {
return userName;
}
public void setUserName ( String userName) {
this . userName = userName;
}
public Integer getUserAge ( ) {
return userAge;
}
public void setUserAge ( Integer userAge) {
this . userAge = userAge;
}
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
this . id = id;
}
}
自定义注解
@Documented
@Retention ( RetentionPolicy . RUNTIME)
@Target ( ElementType . METHOD)
public @interface ExtInsert {
String value ( ) ;
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
@Documented
@Retention ( RetentionPolicy . RUNTIME)
@Target ( ElementType . PARAMETER)
public @interface ExtParam {
String value ( ) ;
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
@Documented
@Retention ( RetentionPolicy . RUNTIME)
@Target ( ElementType . METHOD)
public @interface ExtSelect {
String value ( ) ;
}
封装JDBCUtils
public final class JDBCUtils {
private static String connect;
private static String driverClassName;
private static String URL;
private static String username;
private static String password;
private static boolean autoCommit;
private static Connection conn;
static {
config ( ) ;
}
private static void config ( ) {
driverClassName = "com.mysql.jdbc.Driver" ;
URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8" ;
username = "root" ;
password = "root" ;
autoCommit = false ;
}
private static boolean load ( ) {
try {
Class . forName ( driverClassName) ;
return true ;
} catch ( ClassNotFoundException e) {
System . out. println ( "驱动类 " + driverClassName + " 加载失败" ) ;
}
return false ;
}
private static boolean invalid ( ) {
if ( conn != null ) {
try {
if ( conn. isClosed ( ) || ! conn. isValid ( 3 ) ) {
return true ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return false ;
} else {
return true ;
}
}
public static Connection connect ( ) {
if ( invalid ( ) ) {
load ( ) ;
try {
conn = DriverManager . getConnection ( URL, username, password) ;
} catch ( SQLException e) {
System . out. println ( "建立 " + connect + " 数据库连接失败 , " + e. getMessage ( ) ) ;
}
}
return conn;
}
public static void transaction ( ) {
try {
conn. setAutoCommit ( autoCommit) ;
} catch ( SQLException e) {
System . out. println ( "设置事务的提交方式为 : " + ( autoCommit ? "自动提交" : "手动提交" ) + " 时失败: " + e. getMessage ( ) ) ;
}
}
public static Statement statement ( ) {
Statement st = null ;
connect ( ) ;
transaction ( ) ;
try {
st = conn. createStatement ( ) ;
} catch ( SQLException e) {
System . out. println ( "创建 Statement 对象失败: " + e. getMessage ( ) ) ;
}
return st;
}
private static PreparedStatement prepare ( String SQL, boolean autoGeneratedKeys) {
PreparedStatement ps = null ;
connect ( ) ;
transaction ( ) ;
try {
if ( autoGeneratedKeys) {
ps = conn. prepareStatement ( SQL, Statement . RETURN_GENERATED_KEYS) ;
} else {
ps = conn. prepareStatement ( SQL) ;
}
} catch ( SQLException e) {
System . out. println ( "创建 PreparedStatement 对象失败: " + e. getMessage ( ) ) ;
}
return ps;
}
public static ResultSet query ( String SQL, List < Object > params) {
if ( SQL == null || SQL. trim ( ) . isEmpty ( ) || ! SQL. trim ( ) . toLowerCase ( ) . startsWith ( "select" ) ) {
throw new RuntimeException ( "你的SQL语句为空或不是查询语句" ) ;
}
ResultSet rs = null ;
if ( params. size ( ) > 0 ) {
PreparedStatement ps = prepare ( SQL, false ) ;
try {
for ( int i = 0 ; i < params. size ( ) ; i++ ) {
ps. setObject ( i + 1 , params. get ( i) ) ;
}
rs = ps. executeQuery ( ) ;
} catch ( SQLException e) {
System . out. println ( "执行SQL失败: " + e. getMessage ( ) ) ;
}
} else {
Statement st = statement ( ) ;
try {
rs = st. executeQuery ( SQL) ;
} catch ( SQLException e) {
System . out. println ( "执行SQL失败: " + e. getMessage ( ) ) ;
}
}
return rs;
}
private static Object typeof ( Object o) {
Object r = o;
if ( o instanceof java. sql. Timestamp) {
return r;
}
if ( o instanceof java. util. Date) {
java. util. Date d = ( java. util. Date) o;
r = new java. sql. Date( d. getTime ( ) ) ;
return r;
}
if ( o instanceof Character || o. getClass ( ) == char . class ) {
r = String . valueOf ( o) ;
return r;
}
return r;
}
public static boolean execute ( String SQL, Object . . . params) {
if ( SQL == null || SQL. trim ( ) . isEmpty ( ) || SQL. trim ( ) . toLowerCase ( ) . startsWith ( "select" ) ) {
throw new RuntimeException ( "你的SQL语句为空或有错" ) ;
}
boolean r = false ;
SQL = SQL. trim ( ) ;
SQL = SQL. toLowerCase ( ) ;
String prefix = SQL. substring ( 0 , SQL. indexOf ( " " ) ) ;
String operation = "" ;
switch ( prefix) {
case "create" :
operation = "create table" ;
break ;
case "alter" :
operation = "update table" ;
break ;
case "drop" :
operation = "drop table" ;
break ;
case "truncate" :
operation = "truncate table" ;
break ;
case "insert" :
operation = "insert :" ;
break ;
case "update" :
operation = "update :" ;
break ;
case "delete" :
operation = "delete :" ;
break ;
}
if ( params. length > 0 ) {
PreparedStatement ps = prepare ( SQL, false ) ;
Connection c = null ;
try {
c = ps. getConnection ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
try {
for ( int i = 0 ; i < params. length; i++ ) {
Object p = params[ i] ;
p = typeof ( p) ;
ps. setObject ( i + 1 , p) ;
}
ps. executeUpdate ( ) ;
commit ( c) ;
r = true ;
} catch ( SQLException e) {
System . out. println ( operation + " 失败: " + e. getMessage ( ) ) ;
rollback ( c) ;
}
} else {
Statement st = statement ( ) ;
Connection c = null ;
try {
c = st. getConnection ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
try {
st. executeUpdate ( SQL) ;
commit ( c) ;
r = true ;
} catch ( SQLException e) {
System . out. println ( operation + " 失败: " + e. getMessage ( ) ) ;
rollback ( c) ;
}
}
return r;
}
public static int insert ( String SQL, boolean autoGeneratedKeys, List < Object > params) {
int var = - 1 ;
if ( SQL == null || SQL. trim ( ) . isEmpty ( ) ) {
throw new RuntimeException ( "你没有指定SQL语句,请检查是否指定了需要执行的SQL语句" ) ;
}
if ( ! SQL. trim ( ) . toLowerCase ( ) . startsWith ( "insert" ) ) {
System . out. println ( SQL. toLowerCase ( ) ) ;
throw new RuntimeException ( "你指定的SQL语句不是插入语句,请检查你的SQL语句" ) ;
}
SQL = SQL. trim ( ) ;
SQL = SQL. toLowerCase ( ) ;
if ( params. size ( ) > 0 ) {
PreparedStatement ps = prepare ( SQL, autoGeneratedKeys) ;
Connection c = null ;
try {
c = ps. getConnection ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
try {
for ( int i = 0 ; i < params. size ( ) ; i++ ) {
Object p = params. get ( i) ;
p = typeof ( p) ;
ps. setObject ( i + 1 , p) ;
}
int count = ps. executeUpdate ( ) ;
if ( autoGeneratedKeys) {
ResultSet rs = ps. getGeneratedKeys ( ) ;
if ( rs. next ( ) ) {
var = rs. getInt ( 1 ) ;
}
} else {
var = count;
}
commit ( c) ;
} catch ( SQLException e) {
System . out. println ( "数据保存失败: " + e. getMessage ( ) ) ;
rollback ( c) ;
}
} else {
Statement st = statement ( ) ;
Connection c = null ;
try {
c = st. getConnection ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
try {
int count = st. executeUpdate ( SQL) ;
if ( autoGeneratedKeys) {
ResultSet rs = st. getGeneratedKeys ( ) ;
if ( rs. next ( ) ) {
var = rs. getInt ( 1 ) ;
}
} else {
var = count;
}
commit ( c) ;
} catch ( SQLException e) {
System . out. println ( "数据保存失败: " + e. getMessage ( ) ) ;
rollback ( c) ;
}
}
return var ;
}
private static void commit ( Connection c) {
if ( c != null && ! autoCommit) {
try {
c. commit ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
private static void rollback ( Connection c) {
if ( c != null && ! autoCommit) {
try {
c. rollback ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
public static void release ( Object cloaseable) {
if ( cloaseable != null ) {
if ( cloaseable instanceof ResultSet ) {
ResultSet rs = ( ResultSet ) cloaseable;
try {
rs. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
if ( cloaseable instanceof Statement ) {
Statement st = ( Statement ) cloaseable;
try {
st. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
if ( cloaseable instanceof Connection ) {
Connection c = ( Connection ) cloaseable;
try {
c. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
封装SQLUtils
public class SQLUtils {
public static String [ ] sqlInsertParameter ( String sql) {
int startIndex = sql. indexOf ( "values" ) ;
int endIndex = sql. length ( ) ;
String substring = sql. substring ( startIndex + 6 , endIndex) . replace ( "(" , "" ) . replace ( ")" , "" ) . replace ( "#{" , "" )
. replace ( "}" , "" ) ;
String [ ] split = substring. split ( "," ) ;
return split;
}
public static List < String > sqlSelectParameter ( String sql) {
int startIndex = sql. indexOf ( "where" ) ;
int endIndex = sql. length ( ) ;
String substring = sql. substring ( startIndex + 5 , endIndex) ;
String [ ] split = substring. split ( "and" ) ;
List < String > listArr = new ArrayList < > ( ) ;
for ( String string : split) {
String [ ] sp2 = string. split ( "=" ) ;
listArr. add ( sp2[ 0 ] . trim ( ) ) ;
}
return listArr;
}
public static String parameQuestion ( String sql, String [ ] parameterName) {
for ( int i = 0 ; i < parameterName. length; i++ ) {
String string = parameterName[ i] ;
sql = sql. replace ( "#{" + string + "}" , "?" ) ;
}
return sql;
}
public static String parameQuestion ( String sql, List < String > parameterName) {
for ( int i = 0 ; i < parameterName. size ( ) ; i++ ) {
String string = parameterName. get ( i) ;
sql = sql. replace ( "#{" + string + "}" , "?" ) ;
}
return sql;
}
}
创建提供动态代理的接口
public class SqlSession {
public static < T > T getMapper ( Class classz) {
return ( T ) Proxy . newProxyInstance ( classz. getClassLoader ( ) , new Class [ ] { classz } ,
new MyInvocationHandlerMbatis ( classz) ) ;
}
}
代理类 通过反射持久层接口
public class MyInvocationHandlerMbatis implements InvocationHandler {
private Object object;
public MyInvocationHandlerMbatis ( Object object) {
this . object = object;
}
public Object invoke ( Object proxy, Method method, Object [ ] args) throws Throwable {
System . out. println ( "使用动态代理技术拦截接口方法开始" ) ;
ExtInsert extInsert = method. getDeclaredAnnotation ( ExtInsert . class ) ;
if ( extInsert != null ) {
return extInsert ( extInsert, proxy, method, args) ;
}
ExtSelect extSelect = method. getDeclaredAnnotation ( ExtSelect . class ) ;
if ( extSelect != null ) {
String selectSQL = extSelect. value ( ) ;
ConcurrentHashMap < Object , Object > paramsMap = paramsMap ( proxy, method, args) ;
List < String > sqlSelectParameter = SQLUtils . sqlSelectParameter ( selectSQL) ;
List < Object > sqlParams = new ArrayList < > ( ) ;
for ( String parameterName : sqlSelectParameter) {
Object parameterValue = paramsMap. get ( parameterName) ;
sqlParams. add ( parameterValue) ;
}
String newSql = SQLUtils . parameQuestion ( selectSQL, sqlSelectParameter) ;
System . out. println ( "newSQL:" + newSql + ",sqlParams:" + sqlParams. toString ( ) ) ;
ResultSet res = JDBCUtils . query ( newSql, sqlParams) ;
if ( ! res. next ( ) ) {
return null ;
}
res. previous ( ) ;
Class < ? > returnType = method. getReturnType ( ) ;
Object object = returnType. newInstance ( ) ;
while ( res. next ( ) ) {
Field [ ] declaredFields = returnType. getDeclaredFields ( ) ;
for ( Field field : declaredFields) {
String fieldName = field. getName ( ) ;
Object fieldValue = res. getObject ( fieldName) ;
field. setAccessible ( true ) ;
field. set ( object, fieldValue) ;
}
}
return object;
}
return null ;
}
private Object extInsert ( ExtInsert extInsert, Object proxy, Method method, Object [ ] args) {
String insertSql = extInsert. value ( ) ;
ConcurrentHashMap < Object , Object > paramsMap = paramsMap ( proxy, method, args) ;
String [ ] sqlInsertParameter = SQLUtils . sqlInsertParameter ( insertSql) ;
List < Object > sqlParams = sqlParams ( sqlInsertParameter, paramsMap) ;
String newSQL = SQLUtils . parameQuestion ( insertSql, sqlInsertParameter) ;
System . out. println ( "newSQL:" + newSQL + ",sqlParams:" + sqlParams. toString ( ) ) ;
return JDBCUtils . insert ( newSQL, false , sqlParams) ;
}
private List < Object > sqlParams ( String [ ] sqlInsertParameter, ConcurrentHashMap < Object , Object > paramsMap) {
List < Object > sqlParams = new ArrayList < > ( ) ;
for ( String paramName : sqlInsertParameter) {
Object paramValue = paramsMap. get ( paramName) ;
sqlParams. add ( paramValue) ;
}
return sqlParams;
}
private ConcurrentHashMap < Object , Object > paramsMap ( Object proxy, Method method, Object [ ] args) {
ConcurrentHashMap < Object , Object > paramsMap = new ConcurrentHashMap < > ( ) ;
Parameter [ ] parameters = method. getParameters ( ) ;
for ( int i = 0 ; i < parameters. length; i++ ) {
Parameter parameter = parameters[ i] ;
ExtParam extParam = parameter. getDeclaredAnnotation ( ExtParam . class ) ;
if ( extParam != null ) {
String paramName = extParam. value ( ) ;
Object paramValue = args[ i] ;
paramsMap. put ( paramName, paramValue) ;
}
}
return paramsMap;
}
public Object extInsertSQL ( ) {
return object;
}
}
测试类
public class Test0003 {
public static void main ( String [ ] args) {
UserMapper userMapper = SqlSession . getMapper ( UserMapper . class ) ;
User selectUser = userMapper. selectUser ( "张三" , 644064 ) ;
System . out. println (
"结果:" + selectUser. getUserName ( ) + "," + selectUser. getUserAge ( ) + ",id:" + selectUser. getId ( ) ) ;
}
}