一、实现手写Mybatis三个难点
1、接口既然不能被实例化?那么我们是怎么实现能够调用的?
2、参数如何和sql绑定
3、返回结果
下面是Mybatis接口
二、Demo实现
1、创建Maven工程(开发工具Eclipse)
下一步
下一步
然后点击“完成”
2、配置pom.xml
<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.example</groupId> <artifactId>writeMybatisDemo</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>
3、JDBCUtil工具类
package com.exmaple.orm.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; 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; /** 声明一个 Connection类型的静态属性,用来缓存一个已经存在的连接对象 */ private static Connection conn; static { config(); } /** * 开头配置自己的数据库信息 */ private static void config() { /* * 获取驱动 */ driverClassName = "com.mysql.jdbc.Driver"; /* * 获取URL */ URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8"; /* * 获取用户名 */ username = "root"; /* * 获取密码 */ password = "123456"; /* * 设置是否自动提交,一般为false不用改 */ autoCommit = false; } /** * 载入数据库驱动类 */ private static boolean load() { try { Class.forName(driverClassName); return true; } catch (ClassNotFoundException e) { System.out.println("驱动类 " + driverClassName + " 加载失败"); } return false; } /** * 专门检查缓存的连接是否不可以被使用 ,不可以被使用的话,就返回 true */ private static boolean invalid() { if (conn != null) { try { if (conn.isClosed() || !conn.isValid(3)) { return true; /* * isValid方法是判断Connection是否有效,如果连接尚未关闭并且仍然有效,则返回 true */ } } catch (SQLException e) { e.printStackTrace(); } /* * conn 既不是 null 且也没有关闭 ,且 isValid 返回 true,说明是可以使用的 ( 返回 false ) */ return false; } else { return true; } } /** * 建立数据库连接 */ public static Connection connect() { if (invalid()) { /* invalid为true时,说明连接是失败的 */ /* 加载驱动 */ 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()); } } /** * 创建 Statement 对象 */ public static Statement statement() { Statement st = null; connect(); /* 如果连接是无效的就重新连接 */ transaction(); /* 设置事务的提交方式 */ try { st = conn.createStatement(); } catch (SQLException e) { System.out.println("创建 Statement 对象失败: " + e.getMessage()); } return st; } /** * 根据给定的带参数占位符的SQL语句,创建 PreparedStatement 对象 * * @param SQL * 带参数占位符的SQL语句 * @return 返回相应的 PreparedStatement 对象 */ 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); // 直接执行不带参数的 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; } // 将 java.util.Date 转成 java.sql.Date if (o instanceof java.util.Date) { java.util.Date d = (java.util.Date) o; r = new java.sql.Date(d.getTime()); return r; } // 将 Character 或 char 变成 String 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; /* 表示 执行 DDL 或 DML 操作是否成功的一个标识变量 */ /* 获得 被执行的 SQL 语句的 前缀 */ 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(); } // 执行 DDL 或 DML 语句,并返回执行结果 try { st.executeUpdate(SQL); commit(c); // 提交事务 r = true; } catch (SQLException e) { System.out.println(operation + " 失败: " + e.getMessage()); rollback(c); // 回滚事务 } } return r; } /* * * @param SQL 需要执行的 INSERT 语句 * * @param autoGeneratedKeys 指示是否需要返回由数据库产生的键(自增长) * * @param params 将要执行的SQL语句中包含的参数占位符的 参数值 * * @return 如果指定 autoGeneratedKeys 为 true 则返回由数据库产生的键; 如果指定 autoGeneratedKeys * 为 false 则返回受当前SQL影响的记录数目 */ 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语句"); } // 如果不是 insert 开头开头的语句 if (!SQL.trim().toLowerCase().startsWith("insert")) { System.out.println(SQL.toLowerCase()); throw new RuntimeException("你指定的SQL语句不是插入语句,请检查你的SQL语句"); } // 获得 被执行的 SQL 语句的 前缀 ( 第一个单词 ) SQL = SQL.trim(); SQL = SQL.toLowerCase(); if (params.size() > 0) { // 说明有参数 PreparedStatement ps = prepare(SQL, autoGeneratedKeys); Connection c = null; try { c = ps.getConnection(); // 从 PreparedStatement 对象中获得 它对应的连接对象 } 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); // 获得值并赋值给 var 变量 } } else { var = count; // 如果不需要获得,则将受SQL影像的记录数赋值给 var 变量 } commit(c); } catch (SQLException e) { System.out.println("数据保存失败: " + e.getMessage()); rollback(c); } } else { // 说明没有参数 Statement st = statement(); Connection c = null; try { c = st.getConnection(); // 从 Statement 对象中获得 它对应的连接对象 } catch (SQLException e) { e.printStackTrace(); } // 执行 DDL 或 DML 语句,并返回执行结果 try { int count = st.executeUpdate(SQL); if (autoGeneratedKeys) { // 如果企望获得数据库产生的键 ResultSet rs = st.getGeneratedKeys(); // 获得数据库产生的键集 if (rs.next()) { // 因为是保存的是单条记录,因此至多返回一个键 var = rs.getInt(1); // 获得值并赋值给 var 变量 } } else { var = count; // 如果不需要获得,则将受SQL影像的记录数赋值给 var 变量 } 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(); } } } } }
4、测试JDBC
1)增加测试
public class JdbcTest { public static void main(String[] args) { // #{userName} 替换成? String insertSql = "insert into user(userName,userAge) values(?,?)"; ArrayList<Object> arrayList = new ArrayList<>(); //非线程安全 arrayList.add("Nick"); arrayList.add(30); int insert = JDBCUtils.insert(insertSql, false, arrayList); System.out.println("insert:" + insert); } }
输出结果
2) 查询测试
public static void query() throws SQLException { String selectSql = "select * from User where userName=? and userAge= ? "; ArrayList<Object> arrayList = new ArrayList<>(); //非线程安全 arrayList.add("Nick"); arrayList.add(30); ResultSet res = JDBCUtils.query(selectSql, arrayList); while (res.next()) { String userName = res.getString("userName"); System.out.println("userName:" +userName); } }
输出结果:
三、手写Mybatis注解版本框架-环境搭建
1、创建自定义插入注解
package com.example.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义插入注解 * */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExtInsert { String value(); }
2、自定义参数注解
package com.example.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义参数注解 * */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface ExtParam { String value(); }
3、创建接口UserMapper
package com.example.mapper; import com.example.annotation.ExtInsert; import com.example.annotation.ExtParam; //@Mapper public interface UserMapper { @ExtInsert("insert into user(userName,userAge) values(#{userName},#{userAge})") public int insertUser(@ExtParam("userName") String userName, @ExtParam("userAge")Integer userAge); }
四、基于AOP实现拦截mapper接口
1、使用反射动态拦截 接口方法
package com.example.mybatis.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 使用反射动态拦截 接口方法 * */ public class MyInvocationHandlerMybatis implements InvocationHandler { private Object object; public MyInvocationHandlerMybatis(Object object) { this.object = object; } //proxy,代理对象 。 method: 拦截方法 。 args 方法上的参数值 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("使用动态代理技术拦截接口方法开始"); return 1; } }
2、创建SqlSession类
package com.example.sql; import java.lang.reflect.Proxy; import com.example.mybatis.aop.MyInvocationHandlerMybatis; public class SqlSession { //加载Mapper接口 @SuppressWarnings("unchecked") public static <T> T getMapper(Class<T> classz) throws IllegalArgumentException, InstantiationException, IllegalAccessException { return (T) Proxy.newProxyInstance(classz.getClassLoader(), new Class[]{classz}, new MyInvocationHandlerMybatis(classz)); } }
3、测试
public class Test003 { public static void main(String[] args) throws IllegalArgumentException, InstantiationException, IllegalAccessException { //使用动态代理技术虚拟调用方法 UserMapper userMapper = SqlSession.getMapper(UserMapper.class); int result = userMapper.insertUser("Larry", 40); System.out.println("insert result:" + result); } }
返回结果
五、@extinsert和@extselect注解基本实现思路
1、ExtSelect 注解
/** * 自定义查询注解 * */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExtSelect { String value(); }
2、ExtInsert 注解
/** * 自定义插入注解 * */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExtInsert { String value(); }
3、User 类
package com.example.entity; public class User { 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; } @Override public String toString() { return "User [userName=" + userName + ", userAge=" + userAge + "]"; } }
4、UserMapper 接口
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); }
5、 SQL拼接
package com.exmaple.orm.util; import java.util.ArrayList; import java.util.List; /** * SQL拼接<br> */ public class SQLUtils { /** * 获取Insert语句后面values 参数信息<br> */ 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; } /** * * 获取select 后面where语句 */ 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; } /** * 将SQL语句的参数替换变为?<br> * */ 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) { String sql = "insert into user(userName,userAge) values(#{userName},#{userAge})"; String[] sqlParameter = sqlInsertParameter(sql); for (String string : sqlParameter) { System.out.println(string); } /*List<String> sqlSelectParameter = SQLUtils .sqlSelectParameter("select * from User where userName=#{userName} and userAge=#{userAge} "); for (String string : sqlSelectParameter) { System.out.println(string); }*/ } }
6、完整的MyInvocationHandlerMybatis 类
package com.example.mybatis.aop; 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.example.annotation.ExtInsert; import com.example.annotation.ExtParam; import com.example.annotation.ExtSelect; import com.exmaple.orm.util.JDBCUtils; import com.exmaple.orm.util.SQLUtils; /** * 使用反射动态拦截 接口方法 * */ public class MyInvocationHandlerMybatis implements InvocationHandler { private Object object; public MyInvocationHandlerMybatis(Object object) { this.object = object; } //proxy,代理对象 。 method: 拦截方法 。 args 方法上的参数值 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("使用动态代理技术拦截接口方法开始"); //ExtInsert的封装过程 //1、判断方法上是否存在@ExtInsert注解 ExtInsert extInsert = method.getDeclaredAnnotation(ExtInsert.class); if(extInsert != null){ return exeInsertSQL(extInsert, proxy, method, args); } //二、查询思路 //1判断方法上是否存在@ExtSelect注解 ExtSelect extSelect = method.getDeclaredAnnotation(ExtSelect.class); if(extSelect != null){ // 2、获取SQL语句,获取注解的Select语句 String selectSQL = extSelect.value(); //3、获取方法的参数和SQL参数进行匹配 ConcurrentHashMap<Object, Object> paramMap = paramsMap(proxy, method, args); //4、替换参数变? 传递方式 List<String> sqlSelectParams = SQLUtils.sqlSelectParameter(selectSQL); //5.传递参数 List<Object> sqlParams = new ArrayList<>(); for(String parameterName : sqlSelectParams){ Object parameterValue = paramMap.get(parameterName); sqlParams.add(parameterValue); } // 6.将sql语句换成? String newSql = SQLUtils.parameQuestion(selectSQL, sqlSelectParams); System.out.println("newSQL:" + newSql + ", sqlParams:" +sqlParams.toString() ); //6、调用jdbc底层代码执行语句; ResultSet res = JDBCUtils.query(newSql, sqlParams); //7、使用反射机制实例对象### 获取方法返回的类型,进行实例化 //思路: //1).使用反射机制获取方法类型, //2). 判断是否有结果集,在进行初始化 //3).使用反射机制给对象复制 while(!res.next()){ return null; //System.out.println(query.getObject(1)); } //下标往上移动一位 res.previous(); //1).使用反射机制获取方法类型, Class<?> retrunType = method.getReturnType(); Object object = retrunType.newInstance(); while(res.next()){ //方式一 /*for(String parameterName: sqlSelectParams){ Object resultValue = res.getObject(parameterName); //使用Java的反射赋值 Field field = retrunType.getDeclaredField(parameterName); //私有方法允许访问 field.setAccessible(true); field.set(object, resultValue); }*/ //方式二 获取当前所有的属性 Field[] declaredFields = retrunType.getDeclaredFields(); for(Field field : declaredFields){ String fildName = field.getName(); Object fildVale = res.getObject(fildName); field.setAccessible(true); field.set(object, fildVale); } } return object; } return null; } private ConcurrentHashMap<Object, Object> paramsMap(Object proxy, Method method, Object[] args){ ConcurrentHashMap<Object,Object> paramMap = 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]; //System.out.println("paramName:" + paramName + " paramValue:" + paramValue); paramMap.put(paramName, paramValue); } } return paramMap; } private List<Object> sqlInsertParameter(String[] sqlInsertParameter , ConcurrentHashMap<Object, Object> paramMap){ List<Object> sqlParams = new ArrayList<>(); for(String paramName: sqlInsertParameter){ Object paramValue = paramMap.get(paramName); sqlParams.add(paramValue); } return sqlParams; } public Object exeInsertSQL(ExtInsert extInsert,Object proxy, Method method, Object[] args) { //方法上存在@ExtInsert,获取他的SQL语句 //2、获取SQL语句,获取注解的Insert语句 String insertSql = extInsert.value(); //System.out.println("insertSql:" + insertSql); //3、获取方法的参数和SQL参数进行匹配 //定义一个Map集合,KEY为@ExtParamValue, Value 结果为参数值 ConcurrentHashMap<Object, Object> paramMap = paramsMap(proxy, method, args); //存放sql执行参数--参数绑定过程 String[] sqlInsertParameter = SQLUtils.sqlInsertParameter(insertSql); List<Object> sqlParams = sqlInsertParameter(sqlInsertParameter, paramMap); //4、替换参数变? String newSQL = SQLUtils.parameQuestion(insertSql, sqlInsertParameter); System.out.println("newSQL:" + newSQL + ",sqlParams:" + sqlParams.toString()); //5、调用jdbc底层代码执行语句; return JDBCUtils.insert(newSQL, false, sqlParams); } }
7、测试
1)查询测试
public class Test003 { public static void main(String[] args) throws IllegalArgumentException, InstantiationException, IllegalAccessException { //使用动态代理技术虚拟调用方法 UserMapper userMapper = SqlSession.getMapper(UserMapper.class); User user = userMapper.selectUser("Nick", 30); System.out.println("user:" + user.toString()); } }
返回结果
2)插入结果测试
public class Test003 { public static void main(String[] args) throws IllegalArgumentException, InstantiationException, IllegalAccessException { //使用动态代理技术虚拟调用方法 UserMapper userMapper = SqlSession.getMapper(UserMapper.class); int result = userMapper.insertUser("Tom3", 20); System.out.println("insert result:" + result); } }
返回结果
原文地址:https://www.cnblogs.com/linlf03/p/10878831.html
时间: 2024-10-08 08:13:05