精华内容
下载资源
问答
  • 线程安全问题 多个线程同时运行相同的代码,有可能造成某些变量和预期的...代码演示: import lombok.SneakyThrows; /** * @author layman */ public class Selling01 { public static void main(String[] args) {

    线程安全问题

    • 多个线程同时运行相同的代码,有可能造成某些变量和预期的不一样。

    演示

    【电影院卖票】:

    假设要播放的电影是《孙悟空三打白骨精》,假设电影院有50个座位 (本场电影卖50张票)。

    模拟电影院的售票窗口,实现多个窗口同时卖票(多线程)。

    代码演示:

    import lombok.SneakyThrows;
    
    /**
     * @author layman
     */
    public class Selling01 {
        public static void main(String[] args) {
            //创建线程任务对象
            TicketWindow tt = new TicketWindow();
            //创建三个窗口
            Thread windowA = new Thread(tt,"窗口A");
            Thread windowB = new Thread(tt,"窗口C");
            Thread windowC = new Thread(tt,"窗口C");
    
            //同时卖票
            windowA.start();
            windowB.start();
            windowC.start();
        }
    }
    
    class TicketWindow implements Runnable {
        private int ticket = 50;
        private Long sleepTime = 100L;
    
        /**
         * 卖票
         */
        @SneakyThrows
        @Override
        public void run() {
            while (true) {
                if (ticket > 0) {
                    //模拟出票操作
                    Thread.sleep(sleepTime);
                    String name = Thread.currentThread().getName();
                    System.out.println(name + "正在卖第 " + ticket + " 张票。");
    				ticket--;
                }
            }
        }
    }
    

    运行结果:
    在这里插入图片描述
    出现的问题:

    • 有多个窗口在卖同一张票
    • 有多个窗口在卖不存在的票(第0张票)

    结论

    线程安全问题都是由全局变量静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作。

    一般来说,这个全局变量、静态变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步, 否则的话就可能影响线程安全。

    如何解决线程安全

    当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。

    Java语言提供了线程同步机制 (synchronized)来解决多线程引发的线程安全问题。

    1. 同步代码块。
    2. 同步方法。
    3. Lock锁机制。

    同步代码块

    • 同步代码块: synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

    格式:

    synchronized(同步锁){ 
    	需要同步操作的代码
     }
    

    同步锁:

    对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁。

    1. 锁对象可以是任意类型。
    2. 多个线程对象要使用同一把锁。

    注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁,谁就进入代码块,其他的线程只能在外等待,处于阻塞状态 (BLOCKED)。

    同步方法

    • 同步方法:使用synchronized关键字修饰的方法。能够保证当前线程执行该方法时,其他线程只能在方法外等待。

    格式:

    public synchronized void method(){ 
    	可能会产生线程安全问题的代码
     }
    
    • 问:在同步方法中,同步锁是谁?
    • 答:对于非static方法,同步锁是this(谁调用这个方法,谁就是锁对象)。 对于static方法,是类的字节码对象(类名.class)。

    Lock锁

    java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作。
    同步代码块/同步方法具有的功能Lock都有,除此之外它更强大,更体现面向对象的特点。

    需要手动释放锁对象

     public void lock() : 加锁。
     public void unlock() : 释放锁。
    

    代码演示:

    import lombok.SneakyThrows;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @author layman
     * @date 2021/3/1
     */
    public class Selling01 {
        public static void main(String[] args) {
            //创建线程任务对象
            TicketWindow tt = new TicketWindow();
            //创建三个窗口
            Thread windowA = new Thread(tt,"窗口A");
            Thread windowB = new Thread(tt,"窗口C");
            Thread windowC = new Thread(tt,"窗口C");
    
            //同时卖票
            windowA.start();
            windowB.start();
            windowC.start();
        }
    }
    
    class TicketWindow implements Runnable {
        private int ticket = 50;
        private Long sleepTime = 100L;
        private Lock lock = new ReentrantLock();
        /**
         * 卖票
         */
        @SneakyThrows
        @Override
        public void run() {
            while (true) {
                lock.lock(); //加锁
                if (ticket > 0) {
                    //模拟出票操作
                    Thread.sleep(sleepTime);
    
                    String name = Thread.currentThread().getName();
                    System.out.println(name + "正在卖第 " + ticket + " 张票。");
                    ticket--;
                }
                lock.unlock(); //释放锁
            }
        }
    }
    
    展开全文
  • 利用傅立叶变换进行图像处理的代码演示

    千次阅读 多人点赞 2021-10-05 07:22:04
    前面有篇文件介绍过使用DCT(离散...也可以说,图像中直流和低频区占大部分,高频区占小部分,zhe'yang...https://blog.csdn.net/tugouxp/article/details/117585190这里介绍用离散傅立叶变换进行图像处理的代码演示

    前面有篇文件介绍过使用DCT(离散余弦)变换进行图像处理的例子:

    Matlab一探DCT/IDCT变换在图像压缩中的应用_tugouxp的专栏-CSDN博客绝大多数图像都有一个共同特征,平坦区域和内容缓慢变化的区域占据一幅图像的大部分,而细节区域和内容突变区域则占小部分。也可以说,图像中直流和低频区占大部分,高频区占小部分,zhe'yang...https://blog.csdn.net/tugouxp/article/details/117585190这里介绍用离散傅立叶变换进行图像处理的代码演示。

    方法和思路:

     关于傅立叶变换的实践,可以参考这篇文章:

    图说Fourier变换_tugouxp的专栏-CSDN博客_fourier变换如同熟知的泰勒级数一样,Fourierhttps://blog.csdn.net/tugouxp/article/details/113485640傅立叶变换就是将一个信号曲线分解成若干个正弦曲线,这些正弦的频率代表了原信号曲线的频率变化情况,总的来说就是对原来信号曲线上的不同频率的信号进行分门别类,同一频率下的信号被分到了一个正弦曲线上,这样就有了若干个不同频率的正弦曲线了,而这些正弦曲线中,有些是我们需要的信息,而有些是不需要的信息,我们把不重要的信息过滤掉,即可得到我们想要的信息。

    代码演示:

    高频滤波操作:

    #-*- coding:utf-8 -*-
    import numpy
    import cv2
    import matplotlib.pyplot as plt
    import os
    
    print (os.getcwd())#获得当前目录
    print (os.path.abspath('.'))#获得当前工作目录
     
    #DFT:离散傅里叶变换'
    # 2.OpenCV中的 DFT(Discrete Fourier Transform) 离散傅里叶变换
    img = cv2.imread("./3.jpg")
    # 0.转化为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    rows, cols = gray.shape
     
    # 1.DFT离散傅里叶变换: 空域--〉频域
    dft = cv2.dft(src=numpy.float32(gray), flags=cv2.DFT_COMPLEX_OUTPUT)  # src为灰度图,并且是numpy.float32类型
    print(dft.shape)#两个通道
     
    # 2.中心化: 将低频移动到图像中心
    fftshift = numpy.fft.fftshift(dft)
    # 获取振幅谱(展示图片用): numpy.log()是为了将值限制在[0, 255]
    magnitude_spectrum = numpy.log(cv2.magnitude(fftshift[:, :, 0], fftshift[:, :, 1]))
     
    # 3.滤波操作之低通滤波(去高频,保低频)
    mask = numpy.zeros((rows, cols,2), dtype=numpy.uint8)
    mask[(rows // 2 - 30): (rows // 2 + 30), (cols // 2 - 30): (cols // 2 + 30)] = 1
    fftshift = fftshift * mask
     
    # 4.去中心化: 将低频和高频的位置还原
    ifftshift = numpy.fft.ifftshift(fftshift)
     
    # 5.逆傅里叶变换: 频域--〉空域
    idft = cv2.idft(ifftshift)
     
    # 6.二维向量取模(幅值)
    img_back = cv2.magnitude(idft[:, :, 0], idft[:, :, 1])
     
    # 结合matplotlib展示多张图片
    plt.figure(figsize=(10, 10))
    plt.subplot(221), plt.imshow(gray, cmap="gray"), plt.title("Input Gray Image")
    plt.xticks([]), plt.yticks([])
    plt.subplot(222), plt.imshow(magnitude_spectrum, cmap="gray"), plt.title("Magnitude Spectrum")
    plt.xticks([]), plt.yticks([])
    plt.subplot(223), plt.imshow(img_back, cmap="gray"), plt.title("Image after LPF")
    plt.xticks([]), plt.yticks([])
    plt.subplot(224), plt.imshow(img_back), plt.title("Result in JET")  # 默认cmap='jet'
    plt.xticks([]), plt.yticks([])
    plt.show()

    lena大妈已经快70岁了,这张照片原本是刊登在playboy杂志的一张照片,而且是一张全身裸照(是不是突然很开心),估计大妈本人也没有想到自己年轻时的玉照在全世界的程序员和算法工程中间流传吧。

    运行效果,

    通过上面案例,我们直观地感受到了傅立叶变换在图像去噪方面的实际效果,去掉了高频信号后,无论是灰度图,还是默认色彩图,图像的轮廓都会被软化,界限变得模糊,这是由于图像的噪声以及边缘部位往往梯度变化较大,而梯度较大的地方属于高频信号,所以在去噪的同时会软化图像边缘。

    接下来我们进行一个反向操作,也就是图像高通滤波操作,即去低频信号,留高频信号,看看处理后的图像最终有什么变化。我们这次以numpy中的快速傅立叶变换为例来实现图像高通滤波操作:

    import numpy
    import cv2
    import matplotlib.pyplot as plt
    import os
     
    img = cv2.imread("./3.jpg")
    # 0.转化为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    rows, cols = gray.shape
    print(gray.shape)
     
    # 1.FFT快速傅里叶变换: 空域--〉频域
    fft = numpy.fft.fft2(gray)  # 傅里叶变换,参数为灰度图
    print(fft.shape)
     
    # 2.中心化: 将低频信号移动到图像中心
    fftshift = numpy.fft.fftshift(fft)
    print(numpy.min(numpy.abs(fftshift)))#绝对最低频率信号
    print(numpy.max(fftshift),numpy.min(fftshift))#最高频率信号,最低频率信号
    # 获取振幅谱(展示图片用): numpy.log()是为了将值压缩在[0, 255]附近
    magnitude_spectrum = numpy.log(numpy.abs(fftshift))
    print(numpy.max(magnitude_spectrum),numpy.min(magnitude_spectrum))
     
    # 3.滤波操作之高通滤波(去低频,保高频)
    fftshift[rows // 2 - 50:rows // 2 + 50, cols // 2 - 50: cols // 2 + 50] = 0
    # print(fftshift.shape)
     
    # 4.去中心化: 将剩余的低频和高频的位置还原
    ifftshift = numpy.fft.ifftshift(fftshift)
     
    # 5.逆傅里叶变换: 频域--〉空域
    ifft = numpy.fft.ifft2(ifftshift)
    # print(ifft)
     
    # 6.二维向量取模(幅值)
    img_back = numpy.abs(ifft)
     
    #结合matplotlib展示多张图片
    plt.figure(figsize=(10, 10))
    plt.subplot(221), plt.imshow(gray, cmap="gray"), plt.title("Input Gray Image")
    plt.xticks([]), plt.yticks([])
    plt.subplot(222), plt.imshow(magnitude_spectrum, cmap="gray"), plt.title("Magnitude Spectrum")
    plt.xticks([]), plt.yticks([])
    plt.subplot(223), plt.imshow(img_back, cmap="gray"), plt.title("Image after HPF")
    plt.xticks([]), plt.yticks([])
    plt.subplot(224), plt.imshow(img_back), plt.title("Result in JET")  # 默认cmap='jet'
    plt.xticks([]), plt.yticks([])
    plt.show()

    运行效果:

    频谱中的亮线 证明空域中有 与亮线方向垂直的边缘,因为频谱上每个点所代表的正弦波方向是固定的 x轴上的正弦波就是传播方向向x轴的波

    空域的一条亮线 如果是竖直 就是x方向有突变 换到一维 就像一个方波 理论上是无穷多个不同频率正弦波的叠加 从小到大都有,所以x轴上所有点 即频率都有值 结果是一条亮线。

    图像高通滤波的效果和低通滤波效果刚好相反,从上面案例的结果来看,高通滤波的操作会使图像失去更多的背景细节部分,只保留了图像相应的轮廓界面。这是因为背景部分的图像梯度变化相对轮廓部分的梯度变化较小,图像梯度变化较小的这部分属于低频信号,去除掉这部分低频信号,会使得图像缺少过渡,边缘显得生硬,当去除过多的低频信号时,甚至会让图像变成一副边缘轮廓图。

    既然我们能够通过傅立叶变换对图像进行高通滤波或低通滤波的操作,那么同样也能对图像进行指定任意频段的滤波操作,比如中通滤波就是保留图像中间指定频段的数据,去除高频数据和低频数据的操作,而阻滞滤波刚好是去除图像中间指定频段的数据,保留高频和低频数据。

    FFT变换为什么会出现亮十字?

    我觉得是由于空域的图像实际是乘以了矩形窗rect(x)rect(y)的,所以在频域中心会出现sinc条纹,每条暗线实际上是如下的函数:

    因为每幅图像都有一个举行的边缘突变部分,反映到频谱上就是两条垂直的亮线交于中心点,中心点是直流部分。

    想要验证的话很容易,只要设计一副纯色图片,不对的缩小纯色的范围,保留边缘,看亮线何时出现以及出现的规律即可验证。


    结束!

    展开全文
  • ajax的基本使用(代码演示和讲解)

    千次阅读 2021-01-09 21:08:47
    4.1 扩展 我们可以把上边那段代码改写成支持Promise的形式,这样就可以进行链式调用 function get(url) { return new Promise(function (resolve, reject) { let xhr = new XMLHttpRequest(); xhr.onload = ...

    1. ajax是什么

    • ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
    • AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
    • 传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。ajax通过在后台与服务器进行少量数据交换,这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
      在这里插入图片描述

    2. 基本使用

    function loadData() {
        let xhr;
        if (window.XMLHttpRequest) {
          xhr = new XMLHttpRequest();
        } else {
          xhr = new ActiveXObject("Microsoft.XMLHTTP");
        }
    
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.responseText);
          }
        }
    
        xhr.open("GET","http://127.0.0.1:3001/users",true);
        xhr.send();
      }
    

    3. 对上边代码进行讲解

    3.1 创建XMLHttpRequest 对象

    所有现代浏览器(IE7+、Firefox、Chrome、Safari 以及 Opera)均内建 XMLHttpRequest 对象。创建 XMLHttpRequest 对象的语法:let xhr = new XMLHttpRequest();

    老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 对象:let xhr = new ActiveXObject("Microsoft.XMLHTTP");

    所以为了应对所有的现代浏览器,包括 IE5 和 IE6,应该检查浏览器是否支持 XMLHttpRequest 对象。如果支持,则创建 XMLHttpRequest 对象。如果不支持,则创建 ActiveXObject :

    let xhr;
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
    } else {
      xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    

    3.2 向服务器发送请求

    xhr.open("GET","http://127.0.0.1:3001/users",true);
    xhr.send();
    

    (1)open(method,url,async) 方法规定请求的类型、URL 以及是否异步处理请求。

    • method:请求的类型;GET 或 POST
    • url:要访问的服务器上的位置
    • async:true(异步)或 false(同步),默认为true,这个参数可以不写

    (2)send(string) 将请求发送到服务器

    • 参数string:仅用于 POST 请求

    3.3 接收服务器的响应

    如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseTextresponseXML 属性。

    • responseText:获得字符串形式的响应数据
    • responseXML:获得 XML 形式的响应数据

    3.4 onreadystatechange 事件

    当请求被发送到服务器时,我们需要执行一些基于响应的任务。每当 readyState 改变时,就会触发 onreadystatechange 事件。readyState 属性存有 XMLHttpRequest 的状态信息。

    (1)onreadystatechange:每当 readyState 属性改变时,就会调用该函数。

    (2)readyState:存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。

    • 0: 请求未初始化
    • 1: 服务器连接已建立
    • 2: 请求已接收
    • 3: 请求处理中
    • 4: 请求已完成,且响应已就绪

    (3)status

    • 200: “OK”
    • 404: 未找到页面

    (4)在 onreadystatechange 事件中,我们规定当服务器响应已做好被处理的准备时所执行的任务。当 readyState 等于 4 且状态为 200 时,表示响应已就绪

    注意: onreadystatechange 事件被触发 4 次(0 - 4), 分别是: 0-1、1-2、2-3、3-4,对应着 readyState 的每个变化。

    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(xhr.responseText);
      }
    }
    

    4. 其它方式

    //第一个参数是请求路径,第二个参数是一个函数,当拿到数据后调用该函数
    function get(url,callback) {
      let xhr = new XMLHttpRequest();
      //当请求加载成功之后要调用该函数
      xhr.onload = function() {
        callback(xhr.responseText);
      }
      xhr.open('get',url)
      xhr.send();
    }
    
    get('http://localhost:3001/users',function (data) {
      console.log(data);
    });
    

    4.1 扩展

    我们可以把上边那段代码改写成支持Promise的形式,这样就可以进行链式调用

    function get(url) {
      return new Promise(function (resolve, reject) {
        let xhr = new XMLHttpRequest();
        xhr.onload = function () {
          //使用JSON.parse()将拿到的数据转成JS对象
          resolve(JSON.parse(xhr.responseText));
        }
        xhr.open('get', url)
        xhr.send();
      })
    }
    

    链式调用:

    let data = {};
    get('http://localhost:3001/users')
     .then(function (userData) {
       data.user = userData;
       return get('http://localhost:3001/jobs')
     })
     .then(function (jobsData) {
       data.jobs = jobsData;
       console.log(data);
    })
    

    5. 资料

    https://www.runoob.com/ajax/ajax-tutorial.html

    https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

    https://wangdoc.com/javascript/bom/xmlhttprequest.html

    前端学习交流QQ群,群内学习讨论的氛围很好,大佬云集,期待您的加入:862748629 点击加入

    展开全文
  • Mybatis基于传统dao层的开发(完整代码演示

    千次阅读 多人点赞 2021-02-09 11:57:32
    Mybatis基于传统dao层的开发(完整代码演示)项目结构持久层 Dao 接口持久层 Dao 实现类持久层映射配置测试类 项目结构 持久层 Dao 接口 IUserDao: package com.keafmd.dao; import com.keafmd.domain.User; ...

    Mybatis基于传统dao层的开发(完整代码演示)

    项目结构

    在这里插入图片描述

    持久层 Dao 接口

    IUserDao:

    package com.keafmd.dao;
    
    import com.keafmd.domain.User;
    
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: IUserDao
     * @Description: 用户的持久层接口
     * @author: 牛哄哄的柯南
     * @date: 2021-02-06 19:29
     */
    
    public interface IUserDao {
        /**
         * 查询所有操作
         * @return
         */
        List<User> findAll();
    
        /**
         * 保存用户
         * @param user
         */
        void saveUser(User user);
    
        /**
         * 更新用户
         * @param user
         */
        void updateUser(User user);
    
        /**
         * 根据id删除用户
         * @param id
         */
        void deleteUser(Integer id);
    
        /**
         * 根据id查新用户信息
         * @param id
         * @return
         */
        User findById(Integer id);
    
        /**
         * 根据名称模糊查询
         * @param username
         * @return
         */
        List<User> findByName(String username);
    
        /**
         * 查询总用户数
         * @return
         */
        int findTotal();
    
    
    }
    

    持久层 Dao 实现类

    UserDaoImpl:

    package com.keafmd.dao.impl;
    
    import com.keafmd.dao.IUserDao;
    import com.keafmd.domain.User;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: UserDaoImpl
     * @Description:
     * @author: 牛哄哄的柯南
     * @date: 2021-02-09 11:09
     */
    public class UserDaoImpl implements IUserDao {
        private SqlSessionFactory factory;
    
        public UserDaoImpl(SqlSessionFactory factory){
            this.factory=factory;
        }
    
        public List<User> findAll() {
            //1.根据factory获取SQLSession对象
            SqlSession session = factory.openSession();
            //2.调用SqlSession中的方法,实现查询列表
            List<User> users = session.selectList("com.keafmd.dao.IUserDao.findAll");//参数为能获取配置信息的key
            //3.释放资源
            session.close();
            return users;
        }
    
        public void saveUser(User user) {
            //1.根据factory获取SQLSession对象
            SqlSession session = factory.openSession();
            //2.调用SqlSession中的方法,实现保存
            session.insert("com.keafmd.dao.IUserDao.saveUser",user);
            //3.提交事务
            session.commit();
            //释放资源
            session.close();
        }
    
        public void updateUser(User user) {
            //1.根据factory获取SQLSession对象
            SqlSession session = factory.openSession();
            //2.调用SqlSession中的方法,实现更新
            session.update("com.keafmd.dao.IUserDao.updateUser",user);
            //3.提交事务
            session.commit();
            //释放资源
            session.close();
    
        }
    
        public void deleteUser(Integer id) {
            //1.根据factory获取SQLSession对象
            SqlSession session = factory.openSession();
            //2.调用SqlSession中的方法,实现更新
            session.update("com.keafmd.dao.IUserDao.deleteUser",id);
            //3.提交事务
            session.commit();
            //释放资源
            session.close();
        }
    
        public User findById(Integer id) {
            //1.根据factory获取SQLSession对象
            SqlSession session = factory.openSession();
            //2.调用SqlSession中的方法,实现查询一个
            User user = session.selectOne("com.keafmd.dao.IUserDao.findById",id);//参数为能获取配置信息的key
            //3.释放资源
            session.close();
            return user;
        }
    
        public List<User> findByName(String username) {
            //1.根据factory获取SQLSession对象
            SqlSession session = factory.openSession();
            //2.调用SqlSession中的方法,实现查询列表
            List<User> users = session.selectList("com.keafmd.dao.IUserDao.findByName",username);//参数为能获取配置信息的key
            //3.释放资源
            session.close();
            return users;
        }
    
        public int findTotal() {
            //1.根据factory获取SQLSession对象
            SqlSession session = factory.openSession();
            return session.selectOne("com.keafmd.dao.IUserDao.findTotal");
        }
    }
    

    持久层映射配置

    IUserDao.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="com.keafmd.dao.IUserDao">
    
        <!--配置查询所有-->
        <!--id为方法名称-->
        <select id="findAll" resultType="com.keafmd.domain.User">
            select * from user
        </select>
    
        <!--保存用户-->
        <insert id="saveUser" parameterType="com.keafmd.domain.User">
            <!--配置插入操作后,获取插入的id-->
            <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
                select last_insert_id();
            </selectKey>
            insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday});
        </insert>
    
        <!--更新用户-->
        <update id="updateUser" parameterType="com.keafmd.domain.User">
            update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
        </update>
    
        <!--删除用户-->
        <!--#{id}这里面写个占位符就行-->
        <delete id="deleteUser" parameterType="Integer">
            delete from user where id = #{uid}
        </delete>
    
        <!--根据id查询用户-->
        <select id="findById" parameterType="Integer" resultType="com.keafmd.domain.User">
            select * from user where id = #{id}
        </select>
    
        <!--根据名称模糊查询-->
        <select id="findByName" parameterType="String" resultType="com.keafmd.domain.User">
            <!--select * from user where username like #{name}-->
            <!--value是固定的,源码写固定了,这种了解即可,不推荐-->
            select * from user where username like '%${value}%'
        </select>
    
        <!--查询总用户数-->
        <select id="findTotal" resultType="int">
            select count(id) from user;
        </select>
    
    
    
    </mapper>
    

    测试类

    MybatisTest:

    package com.keafmd.test;
    
    import com.keafmd.dao.IUserDao;
    import com.keafmd.dao.impl.UserDaoImpl;
    import com.keafmd.domain.User;
    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.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.InputStream;
    import java.util.Date;
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: MybatisTest
     * @Description: 测试类,测试crud操作
     * @author: 牛哄哄的柯南
     * @date: 2021-02-08 15:24
     */
    public class MybatisTest {
    
        private InputStream in;
        private IUserDao userDao;
    
        @Before // 用于在测试方法执行前执行
        public void init()throws Exception{
            //1.读取配置文件,生成字节输入流
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建SqlSessionFactory工厂
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(in);
            //3.使用工厂对象创建dao对象
            userDao = new UserDaoImpl(factory);
        }
    
        @After // 用于在测试方法执行后执行
        public void destory() throws Exception{
            //6.释放资源
            in.close();
        }
    
        /**
         * 查询所有
         * @throws Exception
         */
        @Test
        public void testFindAll() throws Exception {
    
            //5.使用代理对象执行方法
            List<User> users = userDao.findAll();
            for (User user : users) {
                System.out.println(user);
            }
    
        }
    
        /**
         * 测试保存操作
         */
        @Test
        public void testSave() throws Exception {
            User user = new User();
            user.setUsername("Keafmd DAO");
            user.setSex("男");
            user.setBirthday(new Date());
            user.setAddress("XXXXXXX");
            System.out.println("保存操作前:"+user);
            //5.执行保存方法
            userDao.saveUser(user);
            System.out.println("保存操作后:"+user);
        }
    
        /**
         * 测试更新
         * @throws Exception
         */
        @Test
        public void testUpdate() throws Exception {
            User user = new User();
            user.setId(51);
            user.setUsername("update DAO");
            user.setSex("男");
            user.setBirthday(new Date());
            user.setAddress("XXXXXXX");
            //5.执行更新方法
            userDao.updateUser(user);
        }
    
        /**
         * 测试删除
         * @throws Exception
         */
        @Test
        public void testDelete() throws Exception {
            //5.执行删除方法
            userDao.deleteUser(46);
        }
    
        /**
         * 查询一个
         * @throws Exception
         */
        @Test
        public void testFindOne() throws Exception {
            //5.执行查询一个方法
            User user = userDao.findById(50);
            System.out.println(user);
        }
    
        /**
         * 根据username模糊查询
         * @throws Exception
         */
        @Test
        public void testFindByName() throws Exception {
            //5.执行模糊查询方法
            List<User> users = userDao.findByName("%王%");
            for (User user : users) {
                System.out.println(user);
            }
        }
    
        /**
         * 查询记录总条数
         * @throws Exception
         */
        @Test
        public void testFindTiotal() throws Exception {
            //5.执行记录总条数
            int total = userDao.findTotal();
            System.out.println(total);
        }
    
    }
    

    以上就是Mybatis基于传统dao层的开发(完整代码演示)的全部内容。

    看完如果对你有帮助,感谢点赞支持!
    如果你是电脑端的话,看到右下角的 “一键三连” 了吗,没错点它[哈哈]

    在这里插入图片描述

    加油!

    共同努力!

    Keafmd

    展开全文
  • (C语言)链表详解 附带代码演示(通俗易懂)

    千次阅读 多人点赞 2021-03-23 19:30:37
    表示为: 这便是最简单的链表,此时已经实现了连接的操作了 利用循环语句,实现多链表的连接 直接上源代码: #include #include typedef struct student { const char *name; int age; student *next; //也可以...
  • Spring Boot+Nacos注册中心+gRPC代码演示 本文实现的是springboot接入nacos注册中心并使用grpc进行服务间通讯的功能,主要用来探索nacos和grpc的使用。 目录 nacos安装 创建服务端 grpc项目搭建 创建客户端 ...
  • 导读 本期将介绍并演示C++ OpenCV使用PaddleOCR做文字识别的步骤与效果。 介绍 百度深度学习框架PaddlePaddle开源的OCR...让OCR更简单 | PaddleOCR+OpenCV实现文字识别步骤与代码演示 本文将介绍C++ OpenCV使用Pa.
  • 本次演示提供处理好的测试数据,以及所有代码,一共6个脚本(我目前写得最详细的教程,也是全网少有的)。 数据的预处理就不演示了,预处理的代码存放在0.pre.R文件中。 以下是肿瘤细胞tsne图和原图的对比,和原文...
  • 本期将介绍并演示PaddleOCR+Python+OpenCV实现车牌识别、身份证信息识别和车票信息识别的步骤与效果。 介绍 百度深度学习框架PaddlePaddle开源的OCR项目PaddleOCR近期霸榜github。使用测试后发现识别效果很好,...
  • 代码 程序分析 程序运行 一个工程中出现两个及以上的main函数 代码 运行结果 分析 三、数据类型 数据各种类型 为什么会有这么多的数据类型? 计算机单位 各个数据类型的大小 注意事项 数据类型的使用 ...
  • 常见排序算法(思路+动图演示+代码演示

    千次阅读 多人点赞 2021-05-14 22:39:46
    原理 整个区间被分为 有序区间 无序区间 每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入 动图演示 代码演示 import java.util.Arrays; import java.util.Random; /** * ClassName: InsertSort * ...
  • 我们前面写的代码里面都在使用 “变量”,或者说在使用内存 内存特点 容量小,速度块,断电之后数据丢失,比较贵 但是内存不能满足我们所有的使用场景。我们在有的时候也希望存储容量大一些,速度稍慢点也没太...
  • 开机自启代码演示

    千次阅读 2020-12-29 14:14:31
    下面看具体代码; 修改注册表 void ChooseInvoke() { CString RegPath = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); char sPath[MAX_PATH] = ""; char sSys[MAX_PATH] = ""; std::string strExe...
  • 从原始的三个输出层解析实现了 boxes, classes, nms 等关键 C++ 代码输出,实现了纯 OpenVINO+OpenCV 版本的 YOLOv5s 模型推理的代码演示。下面就是详细的系统环境与各个部分解释,以及代码实现与演
  • python计算三角形面积详细代码演示

    千次阅读 2021-01-30 02:18:39
    小编在最初学习编程时,经常是每一个代码都认识,但是组合在一起运用的时候就不知道要如何实现了,尤其是基础入门教学计算三角形面积的,跟小编一样不懂的小伙伴可以参考下面现成代码:输入圆的半径计算计算周长和...
  • c++ qt的压缩与解压缩可以使用zlib来实现,也可以用quazip库,quazlib是qt第三方开源库,它的编译依赖zlib,本篇博客介绍如何再win11上使用vs2019 QtCreator编译quazip和zlib源码,并提供代码示例和开发环境配置介绍...
  • 用python画爱心及代码演示

    千次阅读 2020-12-22 12:31:39
    程序员在爱情方式上表达上展现的多种多样,其中现在大火的用编程去编写个表白内容,最受欢迎了,今天小编也尝试了下,一起来看看吧~准备工具:python3画爱心实施步骤:打开编译器,写上code,代码如下:...
  • ORACLE单行函数的详细说明及代码演示 SQL语言中,常用的是数据库软件ORACLE,而在ORACLE中,有一些常用的单行函数,即操作一行数据,返回一个结果。 一.字符函数 字符函数是专门用来处理字符串数据的函数,比较常用...
  • Spring5总述(七)—— 基于JdbcTemplate实现数据库操作(代码演示) 基于JdbcTemPlate实现数据库的添加、删除、修改、查询、批量添加操作
  • 操作系统:FIFO算法详解及代码演示

    千次阅读 2021-05-16 14:54:51
    下面是C++面向对象写法代码。 这个说明一下为什么不用容器Queue。是因为queue并没有迭代器,所以无法去寻找里面是否含有某块页面。 直接使用线性表即可,方便简单且快速。 // 在分页式虚拟存储管理中,要求通过键盘...
  • Mybatis的CRUD操作目录结构完整代码 目录结构 完整代码 pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=...
  • 0 前言 本文介绍一些使用android studio进行简单图像处理的简单需求。 可以在论坛提问。 1 从相册选择图片并显示 2 从相机...需要反复询问权限 从相册中选择单个图片 5 一些初学者代码 uri转mat 修改mat 修改mat roi
  • Flink CEP参考地址基本概念pom 依赖code数据源LoginEvent 实体类业务逻辑代码运行效果图 参考地址 flink cep 官网链接 基本概念 FlinkCEP是在Flink上层实现的复杂事件处理库。 它可以让你在无限事件流中检测出特定的...
  • 通过这篇文章我们将熟练掌握C语言中的各种操作符,表达式求值是如何使用操作符的,表达式求值该注意一些什么呢? 一、操作符 分类: 算术操作符 移位操作符 位操作符 赋值操作符 ...如下代码: ...
  • 基于OpenVINO 2020R04版本演示,有图有代码
  • 1) pi.write(LED4, 0) delay() pi.write(LED1, 0) pi.write(LED2, 1) pi.write(LED3, 0) pi.write(LED4, 0) delay() if __name__ == '__main__': # 版本控制 print("当前版本: ", __version__) main() 代码解读 ...
  • SpringMVC中响应数据和结果视图(完整代码演示

    千次阅读 多人点赞 2021-01-31 17:21:37
    响应数据和结果视图代码目录结构返回值分类字符串voidModelAndView转发和重定向 代码目录结构 User类: package com.Keafmd.domain; import java.io.Serializable; /** * Keafmd * * @ClassName: User * @...
  • 利用HTML5可以绘制很多静态的图像,也可以制作一些炫酷的动画,本文分享了8个利用HTML5和CSS3实现的动画演示,同时也分享了源代码供大家下载参考。1、HTML53D点阵列波浪翻滚动画这个HTML5 Canvas动画非常壮观,给人...
  • 推荐14个可以展示你代码的网站

    千次阅读 2021-03-03 17:10:28
    今天我将跟大家分享一些可以展示你代码的网站,它们都提供在线预览功能,所以别人可以看到你的代码如何运行。它们有时候也被称作“代码广场”。它们不仅仅提供简单的代码展示功能,还提供很多代码协作和...
  • 关于近日log4j漏洞导致的远程执行代码的复现例子,利用JNDI的ldap攻击,使远程服务可能执行了恶意代码

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 850,008
精华内容 340,003
关键字:

代码演示