一、Mybatis主要构件
1.Executor
MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护 2.StatementHandler
封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合 3.ParameterHandler
负责对用户传递的参数转换成JDBC Statement 所需要的参数 4.ResultSetHandler
负责将JDBC返回的ResultSet结果集对象转换成List类型的集合 5.TypeHandler
负责java数据类型和jdbc数据类型之间的映射和转换 6.MappedStatement
MappedStatement维护了一条<select|update|delete|insert>节点的封装 7.SqlSource
负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回 8.BoundSql
9.Configuration
MyBatis所有的配置信息都维持在Configuration对象之中
二、工具类
import java. sql. *;
import java. util. List;
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 ( ) ;
}
}
}
}
}
public static void main ( String[ ] args ) throws SQLException {
String inserSql = "insert into user(userName,userAge) values(?,?)" ;
ArrayList< Object> arrayList = new ArrayList < > ( ) ;
arrayList. add ( "测试1" ) ;
arrayList. add ( 20 ) ;
int insert = JDBCUtils. insert ( inserSql, false , arrayList) ;
System. out. println ( "insert:" + insert) ;
ArrayList< Object> arrayList2 = new ArrayList < > ( ) ;
arrayList2. add ( "测试1" ) ;
arrayList2. add ( 20 ) ;
ResultSet res = JDBCUtils. query ( "select * from User where userName=? and userAge=? " , arrayList2) ;
while ( res. next ( ) ) {
Integer id = res. getInt ( "id" ) ;
String userName = res. getString ( "userName" ) ;
System. out. println ( "id:" + id + ",userName:" + userName) ;
}
}
import java. util. ArrayList;
import java. util. List;
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 static void main ( String[ ] args) {
}
}
三、手写Mybatis
1、Pom依赖
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis</ artifactId>
< version> 3.4.5</ version>
</ dependency>
< 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>
< dependency>
< groupId> com.mchange</ groupId>
< artifactId> c3p0</ artifactId>
< version> 0.9.5.2</ version>
</ dependency>
< dependency>
< groupId> mysql</ groupId>
< artifactId> mysql-connector-java</ artifactId>
< version> 5.1.37</ version>
</ dependency>
< dependency>
< groupId> asm</ groupId>
< artifactId> asm</ artifactId>
< version> 3.3.1</ version>
</ dependency>
2、注解创建
@Documented
@Retention ( RetentionPolicy. RUNTIME)
@Target ( ElementType. METHOD)
public @interface ExtInsert {
String value ( ) ;
}
@Documented
@Retention ( RetentionPolicy. RUNTIME)
@Target ( ElementType. METHOD)
public @interface ExtSelect {
String value ( ) ;
}
@Documented
@Retention ( RetentionPolicy. RUNTIME)
@Target ( ElementType. PARAMETER)
public @interface ExtParam {
String value ( ) ;
}
3、aop实现拦截mapper接口
1)mapper接口的方法需要和SQL语句进行绑定
接口不能被实例化?那么如何实现调用呢?
使用字节码技术创建虚拟子类 使用匿名内部类方式 使用动态代理方式创建代理对象(本次采用的方法) 2)UserMapper接口
import com. sjyl. entity. User;
import com. sjyl. annotation. ExtInsert;
import com. sjyl. annotation. ExtParam;
import com. sjyl. annotation. ExtSelect;
public interface UserMapper {
@ExtInsert ( "insert into user(userName,userAge) values(#{userName},#{userAge})" )
public int insertUser ( @ExtParam ( "userName" ) String userName, @ExtParam ( "userAge" ) Integer userAge) ;
@ExtSelect ( "select * from User where userName=#{userName} and userAge=#{userAge} " )
User selectUser ( @ExtParam ( "userName" ) String name, @ExtParam ( "userAge" ) Integer userAge) ;
}
3)MyInvocationHandlerMybatis
import java. lang. reflect. Field;
import java. lang. reflect. InvocationHandler;
import java. lang. reflect. Method;
import java. lang. reflect. Parameter;
import java. sql. ResultSet;
import java. util. ArrayList;
import java. util. List;
import java. util. concurrent. ConcurrentHashMap;
import com. sjyl. annotation. ExtInsert;
import com. sjyl. annotation. ExtParam;
import com. sjyl. annotation. ExtSelect;
import com. sjyl. util. JDBCUtils;
import com. sjyl. util. SQLUtils;
public class MyInvocationHandlerMybatis implements InvocationHandler {
private Object object;
public MyInvocationHandlerMybatis ( 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;
}
}
import java. lang. reflect. Proxy;
public class SqlSession {
public static < T> T getMapper ( Class classz ) {
return ( T) Proxy. newProxyInstance ( classz. getClassLoader ( ) , new Class [ ] { classz } ,
new MyInvocationHandlerMybatis ( classz) ) ;
}
}
4、测试类
public class App
{
public static void main ( String[ ] args ) throws SQLException {
UserMapper userMapper = SqlSession. getMapper ( UserMapper. class ) ;
User selectUser = userMapper. selectUser ( "测试1" , 20 ) ;
System. out. println (
"结果:" + selectUser. getUserName ( ) + "," + selectUser. getUserAge ( ) + ",id:" + selectUser. getId ( ) ) ;
int insertUserResult = userMapper. insertUser ( "张三" , 644064 ) ;
System. out. println ( "insertUserResult:" + insertUserResult) ;
}
}