MyBatis学习笔记(四)

MyBatis学习笔记(四)

MyBatis在Web当中的应用(模拟转账)

新建工程

首先新建一个JAVA web工程。在这里我们选择Jakarta EE进行快速创建。
Template模板我们选择Web application
选择Tomcat服务器
Build System选择Maven进行构建
在这里插入图片描述

导入依赖

在pom.xml中我们导入mybatis,mysql依赖,如果有需要可以导入日志框架

 <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.11</version>
            </dependency>

            <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
                <version>8.0.31</version>
            </dependency>

配置环境

在这里插入图片描述
我们把根路径设置成/bank

构建HTML页面

首先我们删除最初的jsp文件,我们采用静态页面的方式

首页代码和视图:

我们采用post提交方式 提交到transfer这个路径下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>银行账户转账</title>
</head>
<body>

    <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>

在这里插入图片描述

错误页面代码和视图:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转账失败</title>
</head>
<body>

    <h1>转账失败</h1>
</body>
</html>

在这里插入图片描述

成功页面代码和视图

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转账成功</title>
</head>
<body>

<h1>转账成功</h1>
</body>
</html>

在这里插入图片描述

数据库建立

建立一个t_act表,字段如下:
在这里插入图片描述
默认插入两条记录
一个act001 余额50000
一个act002 余额0
在这里插入图片描述

配置xml文件并写sql语句

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value=""/>
                <property name="username" value=""/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="AccountMapper.xml"/> <!-- -->
    </mappers>
</configuration>

AccountMapper.xml
因为我们要在转账之前确认余额还够不够所以我们需要一个select方法以及转账的update方法

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="hsk123456">


    <select id="selectByActno" resultType="com.example.mybatisweb.pojo.Account">
        select * from t_act where actno = #{actno}
    </select>

    <update id="updateByActno">
        update t_act set balance = #{balance} where actno = #{actno}
    </update>
</mapper>

编写Java代码

编写Dao接口

public interface AccountDao {

    Account selectByActno(String id);

    int updateByActno(Account account);

}

编写Dao接口实现类

这边的Sqlsession还是由之前编写的 SqlSessionUtils类来获取

public class AccountDaoImpl  implements AccountDao {
   

    @Override
    public Account selectByActno(String id) {

        SqlSession session = SqlSessionUtils.getSession();
        Account account = session.selectOne("hsk123456.selectByActno",id);
        session.close();
        return  account;

    }

    @Override
    public int updateByActno(Account account) {
        SqlSession session = SqlSessionUtils.getSession();
        int count = session.update("hsk123456.updateByActno",account);
        session.commit();
        session.close();
        return count;
    }
}

编写POJO类

public class Account {

    private Long id;
    private String actno;
    private Double balance;


    public Account() {
    }

    @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;
    }
}

编写Service类

首先我们定义一个转账方法 参数1:转出方 参数2:收入方 参数3:金额数量。
我们采用先把数据从数据库拿到之后加载到类中也就是内存中
所以我们定义了两个account类对象
下一步:做判断如果余额不足则抛出异常;
接着:开始转账操作
最后把数据更新到数据库中,因为操作了两个记录,所以最后的i必定是2,,如果不是2则抛出异常

public class AccountService {

    private AccountDao accountDao = new AccountDaoImpl();

    public void transfer(String from, String to, double money) throws Exception {

        Account account = accountDao.selectByActno(from);
        Account account1 = accountDao.selectByActno(to);

        if (account.getBalance() < money)
        {
            throw new Exception("no enough");
        }

        account.setBalance(account.getBalance() - money);
        account1.setBalance(account1.getBalance() + money);

        int i = accountDao.updateByActno(account);
        i+= accountDao.updateByActno(account1);
        if (i!=2)
        {
            throw new RuntimeException("未知");
        }


    }
}

编写Servlet类

使用注解进行开发
首先调用req.getParameter()方法获取前端发送过来的数据
之后进行转账,如果成功就是没有抛出异常,那么久跳转到成功的页面,反之,则跳转到失败的页面。

@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {

    private AccountService accountService =  new AccountServiceimpl();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        String fromActno = req.getParameter("fromActno");
        String toActno = req.getParameter("toActno");
        double money = Double.parseDouble(req.getParameter("money"));


        //执行service
        try {
            accountService.transfer(fromActno,toActno,money);
            resp.sendRedirect("/bank/success.html");
        } catch (Exception e) {

            resp.sendRedirect("/bank/error.html");
        }


    }
}

至此我们的最初版就结束了。

但是现在存在一个问题 我们这边没有启用事务,我们可不可以在service类中,再获取一个sqlsession对象呢,然后再提交呢?
答案是不行的。
因为每次获取的sqlsession对象都是一个新的对象,和其他的sqlsession的任何操作不相互关联。
那么我们可以使用Threadlocal类,让sqlsession对象在同一个线程中进行共享

2.0版本如下(通过ThreadLocal实现对象的共享):

更改我们的SqlsessionUtil类

public class SqlSessionUtils {

    private  static SqlSessionFactory sqlSessionFactory;

    static{

        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public  static ThreadLocal<SqlSession> local = new ThreadLocal<>();
	
	//从ThreadLocal加入对象并获取一个实例
    public static SqlSession getSession()
    {
       SqlSession session = local.get();
       if (session == null){
           session = sqlSessionFactory.openSession();
       }
       return session;
       
    }
	//从ThreadLocal取出对象并关闭
    public static void close(SqlSession session){

        if (session!=null)
        {
            session.close();
            local.remove();
        }
    }

}

更改Service类

public class AccountServiceimpl implements AccountService {



    private SqlSession session = SqlSessionUtils.getSession();
    private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String from, String to, double money) throws Exception {


        Account account = accountDao.selectByActno(from);
        Account account1 = accountDao.selectByActno(to);

        if (account.getBalance() < money)
        {
            throw new Exception("no enough");
        }

        account.setBalance(account.getBalance() - money);
        account1.setBalance(account1.getBalance() + money);

        int i = accountDao.updateByActno(account);
        i+= accountDao.updateByActno(account1);
        if (i!=2)
        {
            throw new RuntimeException("未知");
        }
		
		//提交
		session.commit();
		//调用工具类的关闭方法
        SqlSessionUtils.close(session);

    }
}

3.0版本(动态生成Dao接口实现类)

至此我们解决了事务的问题,当然还有一个点可以被解决,就是在Mybatis当中可以帮我们动态生成Dao接口的实现类执行CRUD,那么这个就取代了Dao接口的实现类。
在这之前我们需要更改我们的mapper文件

我们要把命名空间改为Dao类的全类名,因为在底层它是通过找这个路径来进行接口的实现

<mapper namespace="com.example.mybatisweb.dao.AccountDao">

我们的CRUD方法的id名需要与Dao类中的方法名一致,同样他在底层会通过这个生成方法名,并把返回值类型生成

  <select id="selectByActno" resultType="com.example.mybatisweb.pojo.Account">
        select * from t_act where actno = #{actno}
    </select>

接下来我们再次改写我们的Service类

调用session.getMapper()方法,参数需要接口的class文件。

 private AccountDao accountDao = session.getMapper(AccountDao.class);

这样我们的3.0版本就出炉了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄大大ovo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值