Mybatis学习目录
上一篇:(四)手写简单版MyBatis框架
下一篇:(六)Mybatis中接口代理机制及使用
实现功能:银行账户转账
使用技术:HTML + Servlet + MyBatis + Tomcat10
数据库准备:
id BIGINT 主键,自增 账户的id
actno VARCHAR(255) 账户名
balance DECIMAL(10,2) 账户金额
数据:
IDEA中创建Maven WEB应用,使用以下模板
配置Tomcat 10服务器,把项目部署进去
默认创建的maven web应⽤没有java和resources目录
需要自己手动加上
或者修改本地Maven仓库maven-archetype-webapp-1.4.jar中的配置文件
web.xml⽂件的版本较低,可以从tomcat10的样例
删除index.jsp文件,因为我们这个项⽬不使⽤JSP。只使⽤html。
确定pom.xml⽂件中的打方式是war包。
引⼊相关依赖和编译器配置:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
</dependencies>
引⼊相关配置文件,放到resources目录下
mybatis-config.xml Mybatis核心配置文件
ActMapper.xml 账户映射文件
logback.xml 日志配置文件
jdbc.properties 数据库配置文件
jdbc.properties:
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mvc?serverTimezone=Asia/Shanghai
username=root
password=root
mybatis-config.xml:
<?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"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--mysql数据库连接信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--指定Mapper.xml文件的路径,resource是在类的根资源路径下查找-->
<mapper resource="ActMapper.xml"/>
</mappers>
</configuration>
logback.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义⽇志⽂件的存储地址-->
<property name="LOG_HOME" value="/home"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示⽇期,%thread表示线程名,%-5level:级别从左显示5
个字符宽度%msg:⽇志消息,%n是换⾏符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- ⽇志输出级别,logback⽇志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
ActMapper.xml:
<?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">
</mapper>
在webapp下新建一个index.html页面用于用户账户转账,提供form形式进行数据提交
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>银行账户转账</title>
</head>
<body>
<form action="/mybatis_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>
创建dao层(持久化层/数据访问层)
创建service层 (业务逻辑层)
创建web层 (控制层/表示层/表现层)
utils包:将之前编写的SqlSessionUtil工具类拷贝到该包下。
exceptions包:自定义异常
pojo包:普通java类
/**
* 简单的账户类
*/
public class Account {
private Long id;
private String actno;
private Double balance;
public Account() {
}
public Account(Long id, String actno, Double balance) {
this.id = id;
this.actno = actno;
this.balance = balance;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", actno='" + actno + '\'' +
", 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;
}
}
分析dao中⾄少要提供几个方法,才能完成转账:
转账前需要查询余额是否充足:selectByActno
转账时要更新账户:update
AccountDao接口:
/**
* 账户的DAO对象,负责t_act表数据的CRUD
*/
public interface AccountDao {
/**
* 根据账号查询账户信息
* @param actno 账号
* @return 账户信息
*/
Account selectByActno(String actno);
/**
* 更新账户信息
* @param act 被更新的账户对象
* @return 1表示成功,其他表示失败
*/
int updateByActno(Account act);
}
AccountDaoImpl实现类:
public class AccountDaoImpl implements AccountDao{
@Override
public Account selectByActno(String actno) {
SqlSession session = SqlSessionUtil.getSession();
Account account = session.selectOne("selectByActno", actno);
return account;
}
@Override
public int updateByActno(Account act) {
SqlSession session = SqlSessionUtil.getSession();
int count = session.update("updateByActno",act);
return count;
}
}
ActMapper.xml:
<select id="selectByActno" resultType="com.bank.pojo.Account">
select * from t_act where actno=#{actno}
</select>
<update id="updateByActno">
update t_act set balance = #{balance} where actno=#{actno}
</update>
在service编写业务,创建接口
/**
* 账户业务类,负责处理账户
*/
public interface AccountService {
/**
* 转账业务
* @param fromact 转出账户
* @param toact 转入账户
* @param meney 转账金额
*/
void transfer(String fromact,String toact,double meney) throws MoneyNotEnoughException, TransferException;
}
转账前需要查询余额是否充足,不充足需要抛出异常
exceptions编写自定义账户金额不足异常类
/**
* 账户金额不足异常
*/
public class MoneyNotEnoughException extends Exception{
public MoneyNotEnoughException() {
}
public MoneyNotEnoughException(String message) {
super(message);
}
}
转账时要更新账户,两个账户更新不成功需要抛出异常
exceptions编写自定义转账异常类
/**
* 转账异常
*/
public class TransferException extends Exception{
public TransferException() {
}
public TransferException(String message) {
super(message);
}
}
编写业务逻辑层实现类
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao = new AccountDaoImpl();
@Override
public void transfer(String fromact, String toact, double meney) throws MoneyNotEnoughException, TransferException {
//处理事务
SqlSession sqlSession = SqlSessionUtil.getSession();
//1.判断转出账户余额是否充足,不充足提示
Account fromAccount = accountDao.selectByActno(fromact);
if (fromAccount.getBalance() < meney) {
//提示用户
throw new MoneyNotEnoughException("不好意思,账户余额不足");
}
//2.转出账户余额充足,更新转出账户余额
Account toactAccount = accountDao.selectByActno(toact);
fromAccount.setBalance(fromAccount.getBalance() - meney);
/*String s = null;//这里模拟异常,测试事务处理是否成功
s.toString();*/
toactAccount.setBalance(toactAccount.getBalance() + meney);
int count = accountDao.updateByActno(fromAccount);
count += accountDao.updateByActno(toactAccount);
if (count != 2) {
sqlSession.rollback();//事务回滚
throw new TransferException("转账异常,未知原因");
}
sqlSession.commit();//事务提交
SqlSessionUtil.close(sqlSession);
}
}
创建一个类继承HttpServlet,前端是doPost提交,需要覆盖doPost方法
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {
AccountService accountService = new AccountServiceImpl();//为了让这个对象在其他方法也可以使用
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fromactno = request.getParameter("fromactno");
String toactno = request.getParameter("toactno");
double money = Double.parseDouble(request.getParameter("money"));
//调用service的转账方法完成转账(调业务层)
try {
accountService.transfer(fromactno,toactno,money);
response.sendRedirect(request.getContextPath() + "/success.html");
} catch (MoneyNotEnoughException e) {
response.sendRedirect(request.getContextPath() + "/error1.html");
} catch (TransferException e) {
response.sendRedirect(request.getContextPath() + "/error2.html");
}catch (Exception e){
response.sendRedirect(request.getContextPath() + "/error2.html");
}
}
}
success.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>转账成功</title>
</head>
<body>
<h1>转账成功</h1>
</body>
</html>
error1.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>转账报告</title>
</head>
<body>
<h1>余额不足!!!</h1>
</body>
</html>
error2.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>转账报告</title>
</head>
<body>
<h1>转账失败,未知原因!!!</h1>
</body>
</html>
启动Tomcat,浏览器输入http://localhost:8080/mybatis_bank/ (mybatis_bank项目名)
输入数据,点击转账测试
数据库数据改变
输入超过金额数据,点击转账测试
数据库数据没有变化
测试事务是否正常处理,在更新账户之间模拟空指针异常
AccountServiceImpl:
String s = null;
s.toString();