week14_day07_正则表达式&&事务&&ThreadLocal

正则表达式:

概念:
正(确的)(规)则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。
作用:
正则表通常被用来判断、检索、替换那些符合某个模式(规则)的文本。


入门案例:判断输入的数字是否是六位数字。

package regex;

import java.util.Scanner;

/**
 * @author shihao
 * @create 2020-07-12 9:04
 */
public class regex {

    public static void main(String[] args) {
        //判断用户输入的是否是六位数字
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        boolean result = isvalid(s);

        //正则表达式判断输入的是否是六位数字
        boolean result2 = s.matches("\\d{6}");
        //1.最基本的功能就是 匹配一个跟你给定的字符串一模一样的 字符串
        boolean result3 = s.matches("123");

        //2.*匹配最近的一个字符
        boolean result4 = s.matches("zo*");
        //3.可匹配空字符串
        boolean result5 = s.matches("(zo)*");
        //google,gooooooogle
        boolean result6 = s.matches("go{2,}gle");
        boolean result7 = s.matches("z|food");
        boolean result8 = s.matches("(z|f)ood");
        //表示只匹配一个,abc中任意一个
        boolean result9 = s.matches("[abc]");
        //表示匹配a-z中任意一个
        boolean result10 = s.matches("[a-z]");
        //表示不匹配a-z中任意一个
        boolean result11 = s.matches("[^a-z]");
        //如果有[],^表示取反
        //如果没有[],^表示开始的位置,$表示结束的位置
        //也就是说下面这个例子表示的是只能匹配abc
        boolean result12 = s.matches("^abc&");
        boolean result13 = s.matches("\\\\");
        //如果想匹配.就需要使用\来转义
        boolean result14 = s.matches("www\\.cskaoyan\\.com");
        System.out.println(result14);
    }

    /**
     * 判断是否是有效的六位数字
     *
     * @param s
     * @return
     */
    private static boolean isvalid(String s) {
        if (s.length() != 6) {
            return false;
        }
        char[] chars = s.toCharArray();
        //chars.for,然后回车,会直接写成for循环的格式
        for (char aChar : chars) {
            if (aChar < '0' || aChar > '9') {
                return false;
            }
        }
        return true;
    }
}


正则基本规则:

  1. 次数限定符
    在这里插入图片描述
  2. 字符集
    在这里插入图片描述
  3. 特殊字符
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  4. 其他
    注:在java中得用2个\才表示1个\。
    在这里插入图片描述
    在这里插入图片描述
    练习:
package regex;

import java.util.Scanner;

/**
 * @author shihao
 * @create 2020-07-12 10:34
 */
public class exercise {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        //匹配身份证号码 15位、18位、17位+X
        boolean result1 = s.matches("\\d{15}|\\d{18}|\\{17}X");
        //匹配手机号
        //13[0-9]、14[4,8,9]、15[0-9]、168、177、18[0-9]
        boolean result2 = s.matches("(13[0-9]|14[489]|15[0-9]|168|177|18[0-9])\\d{8}");
        System.out.println(result1);
    }
}


ThreadLocal

MainDemo:

/**
 * @author shihao
 * @create 2020-07-12 16:11
 */
public class MainDemo {

    public static void main(String[] args) {
        ThreadLocal threadLocal = new ThreadLocal();
        threadLocal.set("张三");
        String o = (String) threadLocal.get();
        System.out.println(o);
        new MyThread(threadLocal).start();
    }
}

MyThread:

/**
 * @author shihao
 * @create 2020-07-12 16:17
 */
public class MyThread extends Thread {

    ThreadLocal threadLocal = new ThreadLocal();

    public MyThread(ThreadLocal threadLocal) {
        this.threadLocal = threadLocal;
    }

    @Override
    public void run() {
        super.run();
        String o = (String) threadLocal.get();
        System.out.println(o);
    }
}

结果输出的结果是:
在这里插入图片描述
为什么调用MyThread后从ThreadLocal中get到的值是null呢?

可能是线程隔离的原因。

看一下threadLocal的set和get方法源码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
也就是说,在main线程中set了只有在main线程中才能get到,而在mythread线程中get是没法儿get到的。

threadLocal存取数据具有线程隔离性。相同的线程,总可以取出来数据。
一个请求到来,service和dao是不是一个线程?是。
service可以取出来,dao可以取出来?可以。
多用户并发访问threadLocal里面的数据会不会交叉?不会交叉。
threadLocal可以用在事务中吗?必须可以。


事务:
DruidUtils (复制自前面做项目一种的DruidUtils ,并新增了开启事务的功能):

/**
 * MallUser: zsquirrel
 * Date: 2020/4/21
 * Time: 10:59 上午
 */
package com.cskaoyan.transfer.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class DruidUtils {

    private static DataSource dataSource;

    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    static {
        //要用类加载器的一个API来获取绝对路径,可以和servletContext解耦
        // c3p0-config.xml文件放在哪的? src目录 不需要做任何配置,它就可以读取到
        InputStream inputStream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static DataSource getDataSource() {
        return dataSource;
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    /**
     * @param transactional 是否开启事务
     * @return
     * @throws SQLException
     */
    public static Connection getConnection(boolean transactional) throws SQLException {
        //如果要开启事务
        if (transactional) {
            //从threadLocal中get以下看下有没有
            //第一次get肯定是没有的,没有就调用无参的getConnection方法,并在threadLocal中设置这个connection
            //第二次调用这个方法时就能从threadLocal中get到了
            Connection connection = threadLocal.get();
            if (connection == null) {
                connection = getConnection();
                //set的时候是在当前线程中set一个connection,而TransferServiceImpl在用完之后又close
                //close就是将其放回数据库连接池
                //而当前线程中放的还是这个connection,但这个connection已经放回到数据库连接池了,
                //此时这个connection就不能直接使用了
                //Tomcat在处理请求时采用的是线程池,那可能下一个请求到来的时候Tomcat就会分配相同的线程给它
                //那再调用getConnection(boolean transactional)方法不就能直接get到connection了
                //但是这个connection已经被放回数据库连接池了,所以这个时候就不能使用connection了
                //所以就有了releaseConnection方法。
                threadLocal.set(connection);
            }
        }
        return getConnection();
    }

    /**
     * 把当前线程中的connection清空
     */
    public static void releaseConnection() {
        threadLocal.set(null);
    }
}

TransferServlet :

package com.cskaoyan.transfer.controller;

import com.cskaoyan.transfer.service.TransferService;
import com.cskaoyan.transfer.service.TransferServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author shihao
 * @create 2020-07-12 11:42
 */
@WebServlet("/transfer")
public class TransferServlet extends HttpServlet {

    private TransferService transferService = new TransferServiceImpl();

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String borrow = request.getParameter("borrow");
        String lend = request.getParameter("lend");
        String money = request.getParameter("money");
        //校验
        transferService.transfer(borrow, lend, money);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

TransferServiceImpl :

package com.cskaoyan.transfer.service;

import com.cskaoyan.transfer.dao.TransferDao;
import com.cskaoyan.transfer.dao.TransferDaoImpl;
import com.cskaoyan.transfer.utils.DruidUtils;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * @author shihao
 * @create 2020-07-12 15:22
 */
public class TransferServiceImpl implements TransferService {

    private TransferDao transferDao = new TransferDaoImpl();

    /**
     * 事务的代码应该写在service层,dao层其实就是一个个操纵数据库的方法
     * service和dao不是同一个connection,
     * 两个dao方法也不是同一个connection
     * 所以service和dao应当是同一个connection才可以谈事务
     * @param borrow
     * @param lend
     * @param money
     */
    @Override
    public void transfer(String borrow, String lend, String money) {
        //这两个方法,DataSource会取两个connection,没法保障事务
        //所以必须让其在一个connection中执行这两个方法
        Connection connection = null;
        try {
            //开启事务
            connection = DruidUtils.getConnection(true);
            connection.setAutoCommit(false);
            transferDao.transfer(borrow, Double.parseDouble(money));
            transferDao.transfer(lend, -Double.parseDouble(money));
            //没出错就提交
            connection.commit();
        } catch (SQLException e) {
            //出错就rollback
            e.printStackTrace();
            if (connection != null) {
                try {
                    connection.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        } finally {
            //关闭流
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

TransferDaoImpl :

package com.cskaoyan.transfer.dao;

import com.cskaoyan.transfer.utils.DruidUtils;
import org.apache.commons.dbutils.QueryRunner;

import java.sql.SQLException;

/**
 * @author shihao
 * @create 2020-07-12 15:26
 */
public class TransferDaoImpl implements TransferDao {
    @Override
    public void transfer(String borrow, Double money) {
        //QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
        //不传DataSource了,在runner.update中传入connection
        QueryRunner runner = new QueryRunner();
        try {
            runner.update(DruidUtils.getConnection(true),
                    "update account set money = money - ? where name = ?",
                    money, borrow);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

index.jsp:

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2020/7/12
  Time: 11:05
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="<%=request.getContextPath()%>/transfer" method="post">
    转入方:<input type="text" name="borrow"><br>
    转出方:<input type="text" name="lend"><br>
    金额:<input type="number" name="money"><br>
    <input type="submit">
</form>
</body>
</html>

这又遇见了一个bug,老是报NullPointerException,于是我对DruidUtils的静态代码块中的代码进行了如下改动,就发现了报错原因:

    static {
        //要用类加载器的一个API来获取绝对路径,可以和servletContext解耦
        // c3p0-config.xml文件放在哪的? src目录 不需要做任何配置,它就可以读取到
        try {
            FileInputStream fis = new FileInputStream(DruidUtils.class.getResource("/").getPath() + "druid.properties");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //找不到指定文件
        //E:\WangDao\JavaEE\regex_transfer\transfer\target\transfer-1.0-SNAPSHOT\WEB-INF\classes\druid.properties
        //然后我将druid.properties复制到上述目录下,问题解决

        //执行到这步的时候老是报NullPointerException,于是我写了上述代码看看是不是没找到文件
        InputStream inputStream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

-玫瑰少年-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值