MyBatis学习笔记——2
一、MyBatis核心配置文件详解
1.1、environment(环境)
- 一般一个数据库会对应一个SqlSessionFactory对象
- 一个环境environment会对应一个SqlSessionFactory对象
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//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 mapper
PUBLIC "-//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 {
@Test
public 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 configuration
PUBLIC "-//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;
@Override
public 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 {
@Override
public Account selectByActno(String actno) {
SqlSession sqlSession = SqlSessionUtil.openSession();
Account act = (Account)sqlSession.selectOne("selectByActno", actno);
sqlSession.close();
return act;
}
@Override
public 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 mapper
PUBLIC "-//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();
@Override
public 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();
@Override
protected 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{
@Test
public 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 mapper
PUBLIC "-//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接口中方法名一致。