MyBatis学习笔记——2
- 一、MyBatis核心配置文件详解
- 1.1、environment(环境)
- 1.2、transactionManager(事务管理器)
- 1.3、dataSource(数据源)
- 1.4、properties
- 1.5、mapper
- 二、在WEB中应用MyBatis(使用MVC架构模式)
- 2.1、需求描述
- 2.2、数据库设计准备数据
- 2.3、环境搭建
- 2.3.1、前端页面index.html
- 2.3.2、创建pojo包、service包、dao包、web包、utils包
- 2.3.3、定义pojo类:Account
- 2.3.4、编写AccountDao接口,以及AccountDaoImpl实现类
- 2.3.5、AccountDaoImpl中编写了mybatis代码,需要编写SQL映射文件了
- 2.3.6、编写AccountService接口以及AccountServiceImpl
- 2.3.7、编写AccountController
- 2.4、MyBatis对象作用域以及事务问题
- 2.4.1、MyBatis核心对象的作用域
- 2.4.1、事务问题
- 三、javassist生成类
- 3.1、Javassist的使用
- 3.2、使用Javassist动态生成DaoImpl类
- 四、MyBatis中接口代理机制及使用
一、MyBatis核心配置文件详解
1.1、environment(环境)
- 一般一个数据库会对应一个SqlSessionFactory对象
- 一个环境environment会对应一个SqlSessionFactory对象
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--默认使用开发环境--><!--<environments default="dev">--><!--默认使用生产环境--><environments default="production"><!--开发环境--><environment id="dev"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/powernode"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment><!--生产环境--><environment id="production"><transactionManager type="JDBC" /><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><mappers><mapper resource="CarMapper.xml"/></mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="car"><insert id="insertCar">insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})</insert>
</mapper>
package com.powernode.mybatis;import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;public class ConfigurationTest {@Testpublic void testEnvironment() throws Exception{// 准备数据Car car = new Car();car.setCarNum("133");car.setBrand("丰田霸道");car.setGuidePrice(50.3);car.setProduceTime("2020-01-10");car.setCarType("燃油车");// 一个数据库对应一个SqlSessionFactory对象// 两个数据库对应两个SqlSessionFactory对象,以此类推SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();// 使用默认数据库SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession = sqlSessionFactory.openSession(true);int count = sqlSession.insert("insertCar", car);System.out.println("插入了几条记录:" + count);// 使用指定数据库SqlSessionFactory sqlSessionFactory1 = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "dev");SqlSession sqlSession1 = sqlSessionFactory1.openSession(true);int count1 = sqlSession1.insert("insertCar", car);System.out.println("插入了几条记录:" + count1);}
}
1.2、transactionManager(事务管理器)
- 作用:配置事务管理器。指定mybatis具体使用什么方式去管理事务。
- type属性有两个值:
- 第一个:JDBC:使用原生JDBC代码来管理事务
- conn.setAutoCommit(false);
- …
- conn.commit();
- 第二个:MANAGED:mybatis不再负责事务的管理,将事务管理交给其他的JavaEE容器
- spring
- …
- 第一个:JDBC:使用原生JDBC代码来管理事务
- 不区分大小写,但是不能写其他值,只能是二选一:
- jdbc、managed
- 在mybatis中提供了一个事务管理器接口:Transaction
- 该接口下有两个实现类:
- jdbcTransaction
- managedTransaction
- 如果
type="JDBC"
,那么底层会实例化JdbcTransaction
对象。 - 如果
type="MANAGED"
,那么底层会实例化ManagedTransaction
对象
- 该接口下有两个实现类:
当事务管理器是:JDBC
- 采用JDBC的原生事务机制:
- 开启事务:
conn.setAutoCommit(false);
- 处理业务…
- 提交事务:
conn.commit();
- 开启事务:
当事务管理器是:MANAGED
- 交给容器去管理事务,但目前使用的是本地程序,没有容器的支持,当mybatis找不到容器的支持时:没有事务。也就是说只要执行一条DML语句,则提交一次。
1.3、dataSource(数据源)
dataSource配置:
- dataSource被称为数据源。
- dataSource作用是什么?
- 为程序提供Connection对象。(但凡是给程序提供Connection对象的,都叫做数据源。)
- 数据源实际上是一套规范。JDK中有这套规范:
javax.sql.DataSource
(这个数据源的规范,这套接口实际上是JDK规定的。) - 我们自己也可以编写数据源组件,只要实现
javax.sql.DataSource
接口就行了。实现接口当中所有的方法。这样就有了自己的数据源。
比如你可以写一个属于自己的数据库连接池(数据库连接池是提供连接对象的,所以数据库连接池就是一个数据源)。 - 常见的数据源组件有哪些呢【常见的数据库连接池有哪些呢】?
- 阿里巴巴的德鲁伊连接池:druid
- c3p0
- dbcp
- type属性 用来指定数据源的类型,就是指定具体使用什么方式来获取Connection对象:
type属性 有三个值:必须是三选一。
type=“[UNPOOLED
|POOLED
|JNDI
]”- UNPOOLED:不使用数据库连接池技术。每一次请求过来之后,都是创建新的Connection对象。
- POOLED:使用mybatis自己实现的数据库连接池。
- JNDI:集成其它第三方的数据库连接池。
-
JNDI是一套规范。谁实现了这套规范呢?大部分的web容器都实现了JNDI规范:
例如: Tomcat、Jetty、WebLogic、WebSphere,这些服务器(容器)都实现了JNDI规范。
JNDI是: java命名目录接口。Tomcat服务器实现了这个规范。 -
不同配置下的属性不同,通过参考官方手册进行编辑配置
-
提醒:正常使用连接池的话,池中有很多参数是需要设置的。设置好参数,可以让连接池发挥的更好。事半功倍的效果。
-
具体连接池当中的参数如何配置呢?需要反复的根据当前业务情况进行测试。
属性 | 作用 |
---|---|
poolMaximumActiveConnections | 最大的活动的连接数量。默认值10 |
poolMaximumIdleConnections | 最大的空闲连接数量。默认值5 |
poolMaximumCheckoutTime | 强行回归池的时间。默认值20秒 |
poolTimeToWait | 当无法获取到空闲连接时,每隔20秒打印一次日志,避免因代码配置有误,导致傻等。(时长是可以配置的) |
当然,还有其他属性。对于连接池来说,以上几个属性比较重要。
最大的活动的连接数量就是连接池连接数量的上限。默认值10,如果有10个请求正在使用这10个连接,第11个请求只能等待空闲连接。
最大的空闲连接数量。默认值5,如何已经有了5个空闲连接,当第6个连接要空闲下来的时候,连接池会选择关闭该连接对象。来减少数据库的开销。
需要根据系统的并发情况,来合理调整连接池最大连接数以及最多空闲数量。充分发挥数据库连接池的性能。【可以根据实际情况进行测试,然后调整一个合理的数量。】
1.4、properties
mybatis提供了更加灵活的配置,连接数据库的信息可以单独写到一个属性资源文件中,假设在类的根路径下创建jdbc.properties文件,配置如下:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/powernode
在mybatis核心配置文件中引入并使用:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--引入外部属性资源文件--><properties resource="jdbc.properties"><property name="jdbc.username" value="root"/><property name="jdbc.password" value="root"/></properties><environments default="dev"><environment id="dev"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--${key}使用--><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><mapper resource="CarMapper.xml"/></mappers>
</configuration>
properties两个属性:
- resource:这个属性从类的根路径下开始加载。【常用的。】
- url:从指定的url加载,假设文件放在d:/jdbc.properties,这个url可以写成:
file:///d:/jdbc.properties
。注意是三个斜杠哦。
注意:如果不知道mybatis-config.xml文件中标签的编写顺序的话,可以有两种方式知道它的顺序:
- 第一种方式:查看dtd约束文件。
- 第二种方式:通过idea的报错提示信息。【一般采用这种方式】
1.5、mapper
mapper标签用来指定SQL映射文件的路径,包含多种指定方式,这里先主要看其中两种:
第一种:resource,从类的根路径下开始加载【比url常用】
<mappers><mapper resource="CarMapper.xml"/>
</mappers>
如果是这样写的话,必须保证类的根下有CarMapper.xml文件。
如果类的根路径下有一个包叫做test,CarMapper.xml如果放在test包下的话,这个配置应该是这样写:
<mappers><mapper resource="test/CarMapper.xml"/>
</mappers>
第二种:url,从指定的url位置加载
假设CarMapper.xml文件放在d盘的根下,这个配置就需要这样写:
<mappers><mapper url="file:///d:/CarMapper.xml"/>
</mappers>
二、在WEB中应用MyBatis(使用MVC架构模式)
目标:
- 掌握mybatis在web应用中怎么用
- mybatis三大对象的作用域和生命周期
- ThreadLocal原理及使用
- 巩固MVC架构模式
- 为学习MyBatis的接口代理机制做准备
实现功能:
- 银行账户转账
使用技术:
- HTML + Servlet + MyBatis
WEB应用的名称:
- bank
2.1、需求描述
2.2、数据库设计准备数据
2.3、环境搭建
- 配置tomcat
- 在pop文件中引入依赖
- 设计好前端页面
- 导入资源配置文件
2.3.1、前端页面index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>银行账户转账</title>
</head>
<body>
<!--/bank是应用的根,部署web应用到tomcat的时候一定要注意这个名字-->
<form action="/bank/transfer" method="post">转出账户:<input type="text" name="fromActno"/><br>转入账户:<input type="text" name="toActno"/><br>转账金额:<input type="text" name="money"/><br><input type="submit" value="转账"/>
</form>
</body>
</html>
2.3.2、创建pojo包、service包、dao包、web包、utils包
- com.powernode.bank.pojo
- com.powernode.bank.service
- com.powernode.bank.service.impl
- com.powernode.bank.dao
- com.powernode.bank.dao.impl
- com.powernode.bank.web.controller
- com.powernode.bank.exception
- com.powernode.bank.utils:将之前编写的SqlSessionUtil工具类拷贝到该包下。
2.3.3、定义pojo类:Account
package com.powernode.bank.pojo;/*** 银行账户类* @author 老杜* @version 1.0* @since 1.0*/
public class Account {private Long id;private String actno;private Double balance;@Overridepublic String toString() {return "Account{" +"id=" + id +", actno='" + actno + '\'' +", balance=" + balance +'}';}public Account() {}public Account(Long id, String actno, Double balance) {this.id = id;this.actno = actno;this.balance = balance;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getActno() {return actno;}public void setActno(String actno) {this.actno = actno;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}
2.3.4、编写AccountDao接口,以及AccountDaoImpl实现类
分析dao中至少要提供几个方法,才能完成转账:
- 转账前需要查询余额是否充足:selectByActno
- 转账时要更新账户:update
AccountDao
package com.powernode.bank.dao;import com.powernode.bank.pojo.Account;/*** 账户数据访问对象* @author 老杜* @version 1.0* @since 1.0*/
public interface AccountDao {/*** 根据账号获取账户信息* @param actno 账号* @return 账户信息*/Account selectByActno(String actno);/*** 更新账户信息* @param act 账户信息* @return 1表示更新成功,其他值表示失败*/int update(Account act);
}
AccountDaoImpl
package com.powernode.bank.dao.impl;import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;public class AccountDaoImpl implements AccountDao {@Overridepublic Account selectByActno(String actno) {SqlSession sqlSession = SqlSessionUtil.openSession();Account act = (Account)sqlSession.selectOne("selectByActno", actno);sqlSession.close();return act;}@Overridepublic int update(Account act) {SqlSession sqlSession = SqlSessionUtil.openSession();int count = sqlSession.update("update", act);sqlSession.commit();sqlSession.close();return count;}
}
2.3.5、AccountDaoImpl中编写了mybatis代码,需要编写SQL映射文件了
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="account"><select id="selectByActno" resultType="com.powernode.bank.pojo.Account">select * from t_act where actno = #{actno}</select><update id="update">update t_act set balance = #{balance} where actno = #{actno}</update>
</mapper>
2.3.6、编写AccountService接口以及AccountServiceImpl
MoneyNotEnoughException
package com.powernode.bank.exception;/*** 余额不足异常* @author 老杜* @version 1.0* @since 1.0*/
public class MoneyNotEnoughException extends Exception{public MoneyNotEnoughException(){}public MoneyNotEnoughException(String msg){ super(msg); }
}
AppException
package com.powernode.bank.exception;/*** 应用异常* @author 老杜* @version 1.0* @since 1.0*/
public class AppException extends Exception{public AppException(){}public AppException(String msg){ super(msg); }
}
AccountService
package com.powernode.bank.service;import com.powernode.bank.exception.AppException;
import com.powernode.bank.exception.MoneyNotEnoughException;/*** 账户业务类。* @author 老杜* @version 1.0* @since 1.0*/
public interface AccountService {/*** 银行账户转正* @param fromActno 转出账户* @param toActno 转入账户* @param money 转账金额* @throws MoneyNotEnoughException 余额不足异常* @throws AppException App发生异常*/void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException;
}
AccountServiceImpl
package com.powernode.bank.service.impl;import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.dao.impl.AccountDaoImpl;
import com.powernode.bank.exception.AppException;
import com.powernode.bank.exception.MoneyNotEnoughException;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.service.AccountService;public class AccountServiceImpl implements AccountService {private AccountDao accountDao = new AccountDaoImpl();@Overridepublic void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {// 查询转出账户的余额Account fromAct = accountDao.selectByActno(fromActno);if (fromAct.getBalance() < money) {throw new MoneyNotEnoughException("对不起,您的余额不足。");}try {// 程序如果执行到这里说明余额充足// 修改账户余额Account toAct = accountDao.selectByActno(toActno);fromAct.setBalance(fromAct.getBalance() - money);toAct.setBalance(toAct.getBalance() + money);// 更新数据库accountDao.update(fromAct);accountDao.update(toAct);} catch (Exception e) {throw new AppException("转账失败,未知原因!");}}
}
2.3.7、编写AccountController
package com.powernode.bank.web.controller;import com.powernode.bank.exception.AppException;
import com.powernode.bank.exception.MoneyNotEnoughException;
import com.powernode.bank.service.AccountService;
import com.powernode.bank.service.impl.AccountServiceImpl;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 账户控制器* @author 老杜* @version 1.0* @since 1.0*/
@WebServlet("/transfer")
public class AccountController extends HttpServlet {private AccountService accountService = new AccountServiceImpl();@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取响应流response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();// 获取账户信息String fromActno = request.getParameter("fromActno");String toActno = request.getParameter("toActno");double money = Integer.parseInt(request.getParameter("money"));// 调用业务方法完成转账try {accountService.transfer(fromActno, toActno, money);out.print("<h1>转账成功!!!</h1>");} catch (MoneyNotEnoughException e) {out.print(e.getMessage());} catch (AppException e) {out.print(e.getMessage());}}
}
2.4、MyBatis对象作用域以及事务问题
2.4.1、MyBatis核心对象的作用域
-
SqlSessionFactoryBuilder
- 这个类可以被实例化、使用和丢弃,一旦创建了
SqlSessionFactory
,就不再需要它了。 因此SqlSessionFactoryBuilder
实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用SqlSessionFactoryBuilder
来创建多个SqlSessionFactory
实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
- 这个类可以被实例化、使用和丢弃,一旦创建了
-
SqlSessionFactory
SqlSessionFactory
一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用SqlSessionFactory
的最佳实践是在应用运行期间不要重复创建多次,多次重建SqlSessionFactory
被视为一种代码“坏习惯”。因此SqlSessionFactory
的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
-
SqlSession
- 每个线程都应该有它自己的
SqlSession
实例。SqlSession
的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将SqlSession
实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将SqlSession
实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将SqlSession
放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个SqlSession
,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保SqlSession
关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) {// 你的应用逻辑代码 }
- 每个线程都应该有它自己的
2.4.1、事务问题
为了保证service和dao中使用的SqlSession对象是同一个,可以将SqlSession
对象存放到ThreadLocal
当中。修改SqlSessionUtil
工具类:
package com.powernode.bank.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;public class SqlSessionUtil {private static SqlSessionFactory sqlSessionFactory;/*** 类加载时初始化sqlSessionFactory对象*/static {try {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));} catch (Exception e) {e.printStackTrace();}}private static ThreadLocal<SqlSession> local = new ThreadLocal<>();/*** 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。** @return 新的会话对象*/public static SqlSession openSession() {SqlSession sqlSession = local.get();if (sqlSession == null) {sqlSession = sqlSessionFactory.openSession();local.set(sqlSession);}return sqlSession;}/*** 关闭SqlSession对象* @param sqlSession*/public static void close(SqlSession sqlSession){if (sqlSession != null) {sqlSession.close();}local.remove();}
}
修改dao中的方法:AccountDaoImpl中所有方法中的提交commit和关闭close代码全部删除。
三、javassist生成类
3.1、Javassist的使用
我们要使用javassist,首先要引入它的依赖
<dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.29.1-GA</version>
</dependency>
样例代码:
package com.powernode.javassist;import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;import java.lang.reflect.Method;public class JavassistTest {public static void main(String[] args) throws Exception {// 获取类池ClassPool pool = ClassPool.getDefault();// 创建类CtClass ctClass = pool.makeClass("com.powernode.javassist.Test");// 创建方法// 1.返回值类型 2.方法名 3.形式参数列表 4.所属类CtMethod ctMethod = new CtMethod(CtClass.voidType, "execute", new CtClass[]{}, ctClass);// 设置方法的修饰符列表ctMethod.setModifiers(Modifier.PUBLIC);// 设置方法体ctMethod.setBody("{System.out.println(\"hello world\");}");// 给类添加方法ctClass.addMethod(ctMethod);// 调用方法Class<?> aClass = ctClass.toClass();Object o = aClass.newInstance();Method method = aClass.getDeclaredMethod("execute");method.invoke(o);}
}
运行要注意:加两个参数,要不然会有异常。
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/sun.net.util=ALL-UNNAMED
3.2、使用Javassist动态生成DaoImpl类
package com.Smulll.javassist;import com.Smulll.bank.dao.AccountDao;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;import java.lang.reflect.Method;
import java.util.Arrays;public class test1{@Testpublic void testGenerateInterfaceAll() throws Exception {//制造类池ClassPool pool = ClassPool.getDefault();//制造类CtClass ctClass = pool.makeClass("com.Smulll.bank.dao.impl.AccountDaoImpl");//制造接口CtClass ctInterface = pool.makeClass("com/Smulll/bank/dao/AccountDao");//使类实现接口ctClass.addInterface(ctInterface);//实现接口中的方法//获取接口中所有的方法Method[] methods = AccountDao.class.getDeclaredMethods();Arrays.stream(methods).forEach(method -> {// method是接口中的抽象方法// 把method抽象方法给实现了try {// public void delete(){System.out.println(111);}StringBuilder methodCode = new StringBuilder();methodCode.append("public ");//追加修饰符列表methodCode.append(method.getReturnType().getName());//追加返回值类型methodCode.append(" ");methodCode.append(method.getName());methodCode.append("(");//添加参数Class<?>[] parameterTypes = method.getParameterTypes();for (int i = 0; i < parameterTypes.length; i++) {Class<?> parameter = parameterTypes[i];methodCode.append(parameter.getName());methodCode.append(" ");methodCode.append("arg"+i);if (i != parameterTypes.length-1){methodCode.append(",");}}methodCode.append("){System.out.println(11111);");//添加返回值String returnName = method.getReturnType().getSimpleName();//获取返回值类名的简类名if ("int".equals(returnName)){methodCode.append("return 1;");} else if ("String".equals(returnName)) {methodCode.append("return \"hello\";");}methodCode.append("}");CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);//将方法都加到类中ctClass.addMethod(ctMethod);} catch (CannotCompileException e) {e.printStackTrace();}});//在内存中生成类,同时生成的类加载到JVM当中Class<?> aClass = ctClass.toClass();AccountDao accountDao = (AccountDao)aClass.newInstance();//执行里面的方法accountDao.delete();accountDao.insert("acton");accountDao.update("acton",100.00);accountDao.selectByActon("acton");}
}
修改AccountMapper.xml文件:namespace必须是dao接口的全限定名称,id必须是dao接口中的方法名:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.powernode.bank.dao.AccountDao"><select id="selectByActno" resultType="com.powernode.bank.pojo.Account">select * from t_act where actno = #{actno}</select><update id="update">update t_act set balance = #{balance} where actno = #{actno}</update>
</mapper>
四、MyBatis中接口代理机制及使用
好消息!!!其实以上所讲内容mybatis内部已经实现了。直接调用以下代码即可获取dao接口的代理类:
AccountDao accountDao = (AccountDao)sqlSession.getMapper(AccountDao.class);
使用以上代码的前提是:AccountMapper.xml文件中的namespace必须和dao接口的全限定名称一致,id必须和dao接口中方法名一致。