首页 > 其他分享 >mybatis02_Mapper代理开发

mybatis02_Mapper代理开发

时间:2023-03-08 20:23:00浏览次数:48  
标签:Mapper name bookName 代理 BookDao sqlSession book mybatis02 id

1、创建项目并添加依赖、连接数据库,编写mybatis的配置文件

项目结构如下

image-20230302085408248

所需依赖如下(创建的是聚合工程,请根据自己的是实际情况选择合适的版本)

 <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>

        <mybatis.version>3.5.6</mybatis.version>
        <mysql.version>8.0.30</mysql.version>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.18.26</lombok.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!--mybatis核心依赖-->
            <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>${mybatis.version}</version>
            </dependency>

            <!--mysql驱动-->
            <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!--单元测试-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <!--日志-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>

    </dependencyManagement>

核心配置文件mybatis-config.xml文件如下(当然你可以给他起别的名字,官网上写的是mybatis-config.xml)

在mappers标签中采用的是自动扫描的方式,即会扫描所有com.ls.dao下的xml文件或dao接口

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://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="jdbc:mysql://localhost:3306/mybatis?useUnicode=true"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
<!--        <mapper class="com.ls.dao.BookDao"></mapper>-->
        <package name="com.ls.dao"/>
    </mappers>
</configuration>

定义日志输出内容

# 定义输出级别为 debug,输出名称为 stdout
log4j.rootLogger=debug,stdout
# 定义 stdout 的输出采用哪个类来执行
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 定义 stdout 的输出类型的样式布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 定义 stdout 样式布局的消息格式
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

创建数据库并在idea中连接

CREATE TABLE `book` (
  `book_id` int NOT NULL AUTO_INCREMENT,
  `book_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `book_author` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`book_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

2、创建工具类MybatisUtil

​ 前面的mybatis简单入门我们已经知道该框架需要通过流加载配置文件mybatis-config.xml创建工厂SqlSessionFactory并使用工厂生产的对象的openSession(打开一个新的session对象,而且每次使用都是打开一个新的session,假如连续使用多次,则获得的session不是同一个对象,并且使用完需要调用close方法关闭session)获取session,这些都是固定的,我们的目的就是获得session对象,所以直接封装成一工具类,让项目启动时就进行加载以便使用。

/**
 * date: 2023/2/25
 *
 * @author Arc
 */
package com.ls.util;

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 java.io.InputStream;

public class MybatisUtil {

    static SqlSessionFactory sqlSessionFactory = null;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得SqlSession
     *
     * @return
     */
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

3、创建实体类和数据持久层接口、配置映射文件

/**
 * date: 2023/2/25
 *
 * @author Arc
 */
package com.ls.model;

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;

@Data
@Accessors(chain = true)
public class Book {
    private int bookId;
    private String bookName;
    private String bookAuthor;
    private Date createTime;
    private Date updateTime;
}

在dao中已经写好了增删改查的一些方法方便直接复制调试。

package com.ls.dao;

import com.ls.model.Book;
import java.util.List;

public interface BookDao {

    /**
     * 添加图书
     * @param book
     * @return
     */
    int add(Book book);


    /**
     * 根据id查找
     * @param bookId
     * @return
     */
    Book findById(Integer bookId);

    /**
     * 查询所有
     * @return
     */
    List<Book> findAll();

    /**
     * 根据名字查询所有书籍
     * @param bookName
     * @return
     */
    List<Book> findByName(String bookName);

    /**
     * 根据id删除
     * @param bookId
     * @return
     */
    int deleteById(int bookId);

    /**
     * 根据id修改
     * @param book
     * @return
     */
    int updateById(Book book);
}

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace:全路径接口名称
    id:接口中对应的方法名
    parameterType:方法的入参类型
    (#{bookName}:取值
-->
<mapper namespace="com.ls.dao.BookDao">

    <insert id="add" parameterType="com.ls.model.Book">
-- 返回自增长的主键
-- keyProperty的值应该是实体类对应的名字
        <selectKey keyProperty="bookId" order="AFTER" resultType="int">
            select last_insert_id()
        </selectKey>
        insert into book (book_name,book_author,create_time,update_time)
        values (#{bookName},#{bookAuthor},#{createTime},#{updateTime})
    </insert>

    <select id="findById" parameterType="java.lang.Integer" resultType="com.ls.model.Book">
        select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
        from book
        where book_id=#{bookId}
    </select>

    <select id="findAll" resultType="com.ls.model.Book">
        select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
        from book
    </select>

    <select id="findByName" parameterType="java.lang.String" resultType="com.ls.model.Book">
        select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
        from book
-- 拼接字符串容易造成sql注入,在这里$相当于+
--         where book_name like '%${bookName}%'
        where book_name like concat('%',#{bookName},'%')
    </select>

    <delete id="deleteById" parameterType="java.lang.Integer">
        delete from book where book_id=#{bookId}
    </delete>

    <update id="updateById" parameterType="com.ls.model.Book">
        update book set book_name = #{bookName},book_author= #{bookAuthor},update_time = now()
        where book_id = #{bookId}
    </update>
</mapper>

4、编写mapper映射文件和service层

在mapper代理开发中要求mapper.xml文件的名字要和dao层它对应接口的名字相同,且把二者放到同一目录下,但是我们一般会把配置文件都放到resource目录下,所以我们在resource目录下创建与dao接口对应的目录,注意在创建时要使用 “ / ” 来代替 “ . ” ,否则目录不会分层。

image-20230302092349590

image-20230302094152147

/**
 * date: 2023/2/25
 *
 * @author Arc
 */
package com.ls.service;

import com.ls.dao.BookDao;
import com.ls.model.Book;
import com.ls.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.util.Date;
import java.util.List;

public class BookService {

    public static void main(String[] args) {
//        testInsert();
        testFindAll();
//        testFindById();
//        testFindByName();
//        testDeleteById();
//        testUpdateById();
    }

    /**
     * 测试添加
     */
    public static void testInsert() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            //获得BookDao对象
            BookDao bookDao = sqlSession.getMapper(BookDao.class);
            Book book = new Book()
                    .setBookName("bookname").setBookAuthor("author").setCreateTime(new Date()).setUpdateTime(new Date());
            int result = bookDao.add(book);
            System.out.println(result > 0 ? "成功" : "失败");
            sqlSession.commit();
            System.out.println(book);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    /**
     * 测试查找所有
     */
    public static void testFindAll() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            //获得BookDao对象
            BookDao bookDao = sqlSession.getMapper(BookDao.class);
            List<Book> books = bookDao.findAll();
            for (Book book1 : books) {
                System.out.println(book1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    /**
     * 测试根据id查找
     */
    public static void testFindById() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            //获得BookDao对象
            BookDao bookDao = sqlSession.getMapper(BookDao.class);
            Book book = bookDao.findById(2);
            System.out.println(book);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    /**
     * 测试根据书名进行模糊查询
     */
    public static void testFindByName() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            //获得BookDao对象
            BookDao bookDao = sqlSession.getMapper(BookDao.class);
            List<Book> books = bookDao.findByName("my");
            for (Book book : books) {
                System.out.println(book);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    /**
     * 测试根据Id删除
     */
    public static void testDeleteById() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            //获得BookDao对象
            BookDao bookDao = sqlSession.getMapper(BookDao.class);
            int result = bookDao.deleteById(1);
            System.out.println(result>0?"成功":"没有找到对应数据");
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    public static void testUpdateById() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            //获得BookDao对象
            BookDao bookDao = sqlSession.getMapper(BookDao.class);
            Book book = new Book()
                    .setBookId(2).setBookAuthor("junmenmghbai").setBookName("消愁是怎样炼成的");
            int result = bookDao.updateById(book);
            sqlSession.commit();
            System.out.println(result>0?"更新成功":"没有找到对应数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}

5、一些细节

模糊查询的字符串拼接

​ 在dao层中有一个findByName方法,参数是String类型的书名,要求返回所有含有该参数的Book,即模糊查询

 /**
     * 根据名字查询所有书籍
     * @param bookName
     * @return
     */
    List<Book> findByName(String bookName);

我们知道在sql语句中可以用%来表示任意个字符,所以我们可以使用 "$" 表示拼接字符串,等同于字符串拼接中的 "+"

 <select id="findByName" parameterType="java.lang.String" resultType="com.ls.model.Book">
        select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
        from book
		where book_name like '%${bookName}%'
    </select>

但是使用字符串拼接如果用户传参不规范就会产生sql注入的问题,所以我们可以使用内置函数concat()将要取的值与 "%" 拼接起来。

 <select id="findByName" parameterType="java.lang.String" resultType="com.ls.model.Book">
        select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
        from book
        where book_name like concat('%',#{bookName},'%')
    </select>

⬇️两种sql经过编译后

image-20230305144013116

#{ }和$

​ 首先需要了解两个符号的作用 :#{}是一个参数占位符,对于String类型会自动加上"",其他类型不加。由于Mybatis采用预编译,其后的参数不会再进行SQL编译,所以一定程度上防止SQL注入。${}是一个简单的String替换,字符串是什么,解析就是什么。

​ 为什么拼接可能会造成sql注入:假如前端传一个bookName值为“java”,对于 where book_name like #{bookName},对应的sql语句就是 where book_name like "java" ;对于 where book_name like ${bookName},对应的sql语句则是where book_name like bookName。这种情况,当用户传参为bookName && 1=1 的时候,就会产生难以预计的后果。

返回自增长主键

​ 如果往某张表中插入一条数据记录,而该表的主键又是自增长的设置,那么在执行 insert 语句 时,我们一般不会对主键列做操作,主键列会自动生成并插入到表中,但是我们可能需要根据主键再去执行相关的修改或者删除操作。

​ 如果表的主键是自增长设置,那么 mysql 在执行 insert 插入提交之前,会自动生成一个自增长主键,并插入到主键列上。获取自增长的主键列的值,可以通过 mysql 的提供的函数 last_insert_id()可以获取到该值,但是此函数的执行必须要在 insert 语句执行之后才可以,所以在 MyBatis 中如果想要获取刚插入的子增长主键记录,则在 mapper.xml 配置文件中,使用如下配置。

这里注意 keyProperty 的值应该是对应POJO类的属性名,即实体名。

<insert id="add" parameterType="com.ls.model.Book">
-- 返回自增长的主键
        <selectKey keyProperty="bookId" order="AFTER" resultType="int">
            select last_insert_id()
        </selectKey>
        insert into book (book_name,book_author,create_time,update_time)
        values (#{bookName},#{bookAuthor},#{createTime},#{updateTime})
    </insert>

⬇️插入成功后返回bookId=9

image-20230305152315068

标签:Mapper,name,bookName,代理,BookDao,sqlSession,book,mybatis02,id
From: https://www.cnblogs.com/purearc/p/17195977.html

相关文章

  • sanic+nginx配置负载均衡--一台服务器上开启多个站点,用同一个nginx代理
    参考链接:UsingnginxasHTTPloadbalancer1)如果只是想用一个端口转发请求然后调用多个站点(也可以是同一个服务,例如sanic包装的模型服务接口,启动多次)只需在nginx/conf......
  • socks5代理服务搭建
    前言:搭建socks5代理服务选择服务器时尽量选择以下服务器版本:CentOS7.x、Debian7+、Ubuntu14.04+。尤其是不要使用CentOS8.x,说多了都是泪啊。这次的搭建包含两种方式:......
  • 内网穿透的高性能的反向代理应用FRP-自定义404错误页【实践可行版】
    frp简介frp是一个专注于内网穿透的高性能的反向代理应用,支持TCP、UDP、HTTP、HTTPS等多种协议。可以将内网服务以安全、便捷的方式通过具有公网IP节点的中转暴露到公......
  • day87-配置代理服务器
    配置代理服务器在通信时,直接向指定服务器发送请求可能会出现拒绝的情况,使用代理服务器,可以配置解决此问题。原理 设计使用axios包进行ajax请求发送对比Ajax技术是......
  • nginx odoo 多层代理获取真实IP
    https://juejin.cn/post/7067104289520353310网络架构:pc->14.23:7050(nginx)->14.22:8081(nginx)->14.22:8080(web服务)23nginx配置:server{ listen7050;......
  • java动态代理
    1️⃣首先创建需要的接口以及对应实现类来测试代理模式(动态代理)      2️⃣创建动态代理类,去帮我代理一些接口   3️⃣创建一个获取代理对象的工厂 ......
  • Day 14 14.2 代理IP
    代理IP代理IP:反反爬使用代理ip是非常必要的一种反反爬的方式,但是即使使用了代理ip,对方服务器任然会有很多的方式来检测我们是否是一个爬虫,比如:一段时间内,检测IP访问的频率......
  • 分布式数据库代理导出分片大表僵死或卡死原因分析及调优
    1、背景现象****分布式数据库导出分片大表代理卡死或者代理僵死2、 ****分布式数据库导出小表或者不是分片表时发现数据可以导出,但是当数据量大时就没法导出数据,再复现一......
  • Vue 配置代理服务器
    js发ajax请求的几种方式-xhr(原生js自带):newXMLHttpRequest()xhr.open()xhr.send()-jQuery:$.get()$.post-axios(推荐)-fetch(windows对象自带):有致命......
  • js代理和期约
    判断类型时除了用typeof还可以用instanceofpersioninstanceofObjectforin用于枚举对象中的非符号键属性,forin不能保证返回的对象forof用于遍历可迭代对象的元素......