2022尚硅谷SSM框架跟学MyBatis基础一

2022尚硅谷SSM框架跟学 一MyBatis

框架图

MyBatis

1、MyBatis简介

1.1MyBatis历史

MyBatis历史

1.2MyBatis特性

MyBatis特性

1.3MyBatis下载

MyBatis下载地址:下载地址
下载地址
下载版本

1.4和其它持久化层技术对比


JDBC

  1. SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
  2. 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
  3. 代码冗长,开发效率低

Hibernate 和 JPA

  1. 操作简便,开发效率高
  2. 程序中的长难复杂 SQL 需要绕过框架
  3. 内部自动生产的 SQL,不容易做特殊优化
  4. 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难。
  5. 反射操作太多,导致数据库性能下降

MyBatis

  1. 轻量级,性能出色
  2. SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
  3. 开发效率稍逊于HIbernate,但是完全能够接受

2.搭建MyBatis

2.1开发环境

IDE:idea 2021.3
构建工具:maven 3.6.3
MySQL版本:MySQL 5.7
MyBatis版本:MyBatis 3.5.7

MySQL不同版本的注意事项
1、驱动类driver-class-name
MySQL 5版本使用jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver
MySQL 8版本使用jdbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver
2、连接地址url
MySQL 5版本的url,要注意设置编码:
jdbc:mysql://localhost:3306/ssm
MySQL 8版本的url要注意设置时区:
jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value is unrecognized or represents more

 2.2创建maven工程

创建Maven工程,之后查看JDK版本

 配置Maven的相关信息

 配置JDK

 

 新建一个Module

 配置Module

 Name:mybatis-helloworld
GroupId:com.atguigu.mybatis
ArtifactId:mybatis-helloworld

 输入相关名称和Maven坐标

 (1)打包方式:jar

    <!-- 打包方式 -->
    <packaging>jar</packaging>

配置打包方式

 因为Mybatis与JDBC打交道,无需配置war包

 (2)引入依赖

    <dependencies>
        <!-- Mybatis核心 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.20</version>
        </dependency>
    </dependencies>

引入依赖后如果报红可以尝试如下方法

-DarchetypeCatalog=internal

 输入指令后,点击Apply后点击ok然后重启IDEA,报红消失,查看Maven中是否创建了依赖

(3)创建数据库

CREATE DATABASE `ssm`; 

 (4)建表

CREATE TABLE `t_user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(20) DEFAULT NULL,
  `password` VARCHAR(20) DEFAULT NULL,
  `age` INT(11) DEFAULT NULL,
  `gender` CHAR(1) DEFAULT NULL,
  `email` VARCHAR(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

直接用sqlyog创建也可

 (5)创建实体类

com.atguigu.mybatis.pojo.User

package com.atguigu.mybatis.pojo;

/**
 * @ClassName: User
 * @Description:
 * @Author: wty
 * @Date: 2023/1/1
 */

public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private String gender;
    private String email;

    public User() {
    }

    public User(Integer id, String username, String password, Integer age, String gender, String email) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
        this.gender = gender;
        this.email = email;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

2.3创建MyBatis的核心配置文件

习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合Spring之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。
核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息
核心配置文件存放的位置是src/main/resources目录下

查看官网文档
查看官网文档
拷贝指令

如下:

<?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>
    <!-- 配置连接数据库的环境(多个) -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="hsp"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 引入MyBatis的映射文件 -->
    <mappers>
        <mapper resource=""/>
    </mappers>
</configuration>

标签说明
标签说明

2.4创建mapper接口

MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类。
创建mapper接口

package com.atguigu.mybatis.mapper;

/**
 * @InterfaceName: UserMapper
 * @Description:
 * @Author: wty
 * @Date: 2023/1/1
 */

public interface UserMapper {
    /**
     * @param
     * @return int
     * @description //增添一条数据
     * @date 2023/1/1 21:55
     * @author wty
     **/
    int insertUser();
}

2.5创建MyBatis的映射文件

相关概念:ORM(Object Relationship Mapping)对象关系映射。
对象:Java的实体类对象
关系:关系型数据库
映射:二者之间的对应关系

1、映射文件的命名规则:
表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表的操作
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
MyBatis映射文件存放的位置是src/main/resources/mappers目录下
2、 MyBatis中可以面向接口操作数据,要保证两个一致:
a>mapper接口的全类名和映射文件的命名空间(namespace)保持一致
b>mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致

存放映射文件
命名与实体类相同

去官方文档查看映射文件的范例
映射文件

<?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.atguigu.mybatis.mapper.UserMapper">
    <!--
        mapper接口和映射文件要保证两个一致
        1.mapper接口的权和类名和映射文件的namespace一致
        2.mapper接口中的方法的方法名要和映射文件中的sql的id保持一致
     -->

    <!-- int insertUser(); -->
    <!-- 书写sql语句 -->
    <insert id="insertUser">
        insert into t_user
        values (null, 'admin', MD5('123456'), 23, '男', 'hsp@126.com')
    </insert>

</mapper>

两个一致性
一致性

配置xml文件
配置xml

    <!-- 引入MyBatis的映射文件 -->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
2.6通过junit测试功能

创建测试类
创建测试类

SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的
会话)
SqlSessionFactory:是“生产”SqlSession的“工厂”。
工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的
相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。

package com.atguigu.mybatis.test;

import com.atguigu.mybatis.mapper.UserMapper;
import com.atguigu.mybatis.pojo.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.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @ClassName: MyBatisTest
 * @Description:
 * @Author: wty
 * @Date: 2023/1/1
 */

public class MyBatisTest {
    @Test
    public void testInsert() throws IOException {
        // 获取核心配置文件的输入流
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        // 获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        // 获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        // 获取sql的会话对象sqlSession,是MyBatis提供的操作数据库的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 代理模式:获取UserMapper的代理实现对象,通过获取User类对象可以获取接口的对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 调用mapper接口中的方法,实现添加用户信息的功能
        int i = mapper.insertUser();
        System.out.println("结果:" + i);

        // 关闭会话
        sqlSession.close();

    }
}

测试结果
测试结果

里虽然结果是1,但是没有设置事务,所以没有提交,需要设置一下

        // 提交事务
        sqlSession.commit();

添加成功
添加成功

sqlSession获取sql执行语句的另一种方式
sqlSession获取sql执行语句的另一种方式

package com.atguigu.mybatis.test;

import com.atguigu.mybatis.mapper.UserMapper;
import com.atguigu.mybatis.pojo.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.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @ClassName: MyBatisTest
 * @Description:
 * @Author: wty
 * @Date: 2023/1/1
 */

public class MyBatisTest {
    @Test
    public void testInsert() throws IOException {
        // 获取核心配置文件的输入流
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        // 获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        // 获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        // 获取sql的会话对象sqlSession,是MyBatis提供的操作数据库的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        /*// 代理模式:获取UserMapper的代理实现对象,通过获取User类对象可以获取接口的对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 调用mapper接口中的方法,实现添加用户信息的功能
        int i = mapper.insertUser();
         */

        // 提供sql的唯一标识找到sql并执行,唯一标识是namespace.id
        int i = sqlSession.insert("com.atguigu.mybatis.mapper.UserMapper.insertUser");

        System.out.println("结果:" + i);

        // 提交事务
        sqlSession.commit();

        // 关闭会话
        sqlSession.close();

    }
}

执行前先截断表
执行前先截断表

截断表:底层删除表并创建一个一模一样的表,自增主键从1开始
清除表:会清除表中的数据,自增主键继续自增
结果
结果

动提交事务
自动提交事务

package com.atguigu.mybatis.test;

import com.atguigu.mybatis.mapper.UserMapper;
import com.atguigu.mybatis.pojo.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.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @ClassName: MyBatisTest
 * @Description:
 * @Author: wty
 * @Date: 2023/1/1
 */

public class MyBatisTest {
    @Test
    public void testInsert() throws IOException {
        // 获取核心配置文件的输入流
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        // 获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        // 获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        // 获取sql的会话对象sqlSession,是MyBatis提供的操作数据库的对象
        //SqlSession sqlSession = sqlSessionFactory.openSession();

        // 设置事务自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        /*// 代理模式:获取UserMapper的代理实现对象,通过获取User类对象可以获取接口的对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 调用mapper接口中的方法,实现添加用户信息的功能
        int i = mapper.insertUser();
         */

        // 提供sql的唯一标识找到sql并执行,唯一标识是namespace.id
        int i = sqlSession.insert("com.atguigu.mybatis.mapper.UserMapper.insertUser");

        System.out.println("结果:" + i);

        // 提交事务,上面设置了自动提交这里就可以注释了
        //sqlSession.commit();

        // 关闭会话
        sqlSession.close();

    }
}

查看结果
2条结果

2.7加入log4j日志功能
(1)加入依赖

在pom.xml中加入依赖加入依赖

        <!-- log4j日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
(2)加入log4j的配置文件

创建配置文件
创建配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}
%m (%F:%L) \n"/>
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug"/>
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info"/>
    </logger>
    <root>
        <level value="debug"/>
        <appender-ref ref="STDOUT"/>
    </root>
</log4j:configuration>

执行即可,查看结果
输出结果

日志的级别
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细

3.核心配置文件详解

先阅读源码

// invoke 方法
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
    return this.mapperMethod.execute(sqlSession, args);
}
// execute方法
public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        Object param;
        switch(this.command.getType()) {
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            break;

           

核心配置文件中的标签必须按照固定的顺序:
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?

,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?

4.MyBatis的增删改查

创建工具类
创建工具类

package com.atguigu.mybatis.utils;

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

/**
 * @ClassName: SqlSessionUtil
 * @Description:工具类
 * @Author: wty
 * @Date: 2023/1/1
 */

public class SqlSessionUtil {
    /**
     * @param
     * @return org.apache.ibatis.session.SqlSession
     * @description //获取SqlSession对象
     * @date 2023/1/1 23:51
     * @author wty
     **/
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        InputStream is = null;
        // 获取核心配置文件的输入流
        try {
            is = Resources.getResourceAsStream("mybatis-config.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        // 获取sqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        // 自动开启事务,并且创建sqlSession对象
        sqlSession = sqlSessionFactory.openSession(true);

        return sqlSession;
    }
}

4.1新增
4.2删除

UserMapper接口中新增方法

    /**
     * @param
     * @return int
     * @description //删除id = 5 的用户信息
     * @date 2023/1/2 0:07
     * @author wty
     **/
    int deleteUser();

UserMapper.xml中添加sql语句

    <!-- int deleteUser() -->
    <delete id="deleteUser">
        delete
        from t_user
        where id = 5
    </delete>

MyBatisTest.java中新增删除测试类

    @Test
    public void deleteUser() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        // 获取mapper对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 调用接口
        int i = mapper.deleteUser();

        System.out.println("结果:" + i);

        sqlSession.close();
    }

执行结果
执行结果

数据库结果
数据库结果

4.3修改

UserMapper接口中新增方法

    /**
     * @param
     * @return int
     * @description //修改一条数据
     * @date 2023/1/1 21:55
     * @author wty
     **/
    int updateUser();

UserMapper.xml中添加sql语句

    <!-- int updateUser(); -->
    <update id="updateUser">
        update t_user
        set username = 'hsp',
            password = '123'
        where id = 1
    </update>

MyBatisTest.java中新增修改测试类

 @Test
    public void testUpdate() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        // 代理模式:获取代理实现类
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 调用mapper接口中的方法,实现修改用户信息的功能
        int i = mapper.updateUser();

        System.out.println("结果:" + i);

        sqlSession.close();
    }

执行结果
执行结果
修改结果
修改结果

4.4查询一个实体类对象

UserMapper接口中新增方法

    /**
     * @param
     * @return com.atguigu.mybatis.pojo.User
     * @description //根据ID查询用户
     * @date 2023/1/2 11:06
     * @author wty
     **/
    User getUserById();

UserMapper.xml中添加sql语句

    <!-- User getUserById(); -->
    <select id="getUserById">
        select *
        from t_user
        where id = 1
    </select>

MyBatisTest.java中新增查询测试类

    @Test
    public void getUserByid() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user = mapper.getUserById();

        System.out.println("对象:" + user.toString());

        sqlSession.close();
    }

如果是当前的代码,执行会报错

### Cause: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'com.atguigu.mybatis.mapper.UserMapper.getUserById'.  It's likely that neither a Result Type nor a Result Map was specified.

直接执行报错
更改一下UserMapper.xml的配置文件

    <!-- User getUserById(); -->
    <!-- resultType设置结果类型,即查询结果需要转换成的Java类型 -->
    <!-- resultMap自定义映射,处理多对一或者一对多的元素关系 -->
    <!-- resultType和resultMap二者必须存在一个,但是不许二者都存在 -->
    <select id="getUserById" resultType="com.atguigu.mybatis.pojo.User">
        select *
        from t_user
        where id = 1
    </select>

再去MyBatisTest.java中执行一下
执行结果
执行结果

4.5查询list集合

UserMapper接口中新增方法

    /**
     * @param
     * @return java.util.List<com.atguigu.mybatis.pojo.User>
     * @description //查询所有的User返回合集
     * @date 2023/1/2 11:23
     * @author wty
     **/
    List<User> getAllUser();

UserMapper.xml中添加sql语句
这里要注意查询结果需要先转换成实体类User类型,然后存放在集合List中

    <!-- List<User> getAllUser(); -->
    <select id="getAllUser" resultType="com.atguigu.mybatis.pojo.User">
        select *
        from t_user
    </select>

MyBatisTest.java中新增查询测试类

    @Test
    public void getAllUser() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        List<User> list = mapper.getAllUser();

        System.out.println("查询结果:");
        list.forEach(System.out::println);

        sqlSession.close();
    }

执行结果
查询结果

4.6核心配置文件详解
(1)环境environments、environment和数据源dataSource解释

核心配置文件mybatis-config.xml
配置环境environments、environment和数据源dataSource解释

    <!-- 配置连接数据库的环境(多个) -->
    <!-- default指定具体使用哪个环境 -->
    <environments default="development">
        <!-- 开发环境 -->
        <!-- id:是环境的唯一标识不允许重复 -->
        <environment id="development">
            <!-- 事务的管理方式 事务管理器
                 type:JDBC  MANAGED
                 JDBC表示使用JDBC中原生的事务管理方式
                 MANAGED表示被管理的,例如spring整合MyBatis的时候,交给spring管理
             -->
            <transactionManager type="JDBC"/>
            <!-- dataSource数据源
                 type:设置数据源的类型
                 type: POOLED UNPOOLED JNDI
                 POOLED表示使用数据库连接池
                 UNPOOLED表示不适用数据库连接池
                 JNDI表示使用上下文中的数据源
             -->
            <dataSource type="POOLED">
               <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="hsp"/>
            </dataSource>
        </environment>

        <!-- 测试环境 -->
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="hsp"/>
            </dataSource>
        </environment>
    </environments>

创建数据库配置文件 jdbc.properties
创建数据库配置文件
配置数据库连接

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
username=root
password=hsp

配置数据库连接

(2)核心配置文件mybatis-config.xml增加 ${}方式和properties

核心配置文件mybatis-config.xml增加 ${}方式和properties映射数据库配置文件

    <!-- 引入properties文件,此后可以在当前文件中使用${key}的形式访问value -->
    <properties resource="jdbc.properties"></properties>

    <!-- 配置连接数据库的环境(多个) -->
    <!-- default指定具体使用哪个环境 -->
    <environments default="development">
        <!-- 开发环境 -->
        <!-- id:是环境的唯一标识不允许重复 -->
        <environment id="development">
            <!-- 事务的管理方式 事务管理器
                 type:JDBC  MANAGED
                 JDBC表示使用JDBC中原生的事务管理方式
                 MANAGED表示被管理的,例如spring整合MyBatis的时候,交给spring管理
             -->
            <transactionManager type="JDBC"/>
            <!-- dataSource数据源
                 type:设置数据源的类型
                 type: POOLED UNPOOLED JNDI
                 POOLED表示使用数据库连接池
                 UNPOOLED表示不适用数据库连接池
                 JNDI表示使用上下文中的数据源
             -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

数据库配置文件和核心配置文件一一对应
数据库配置文件和核心配置文件一一对应

(3)核心配置文件中标签的顺序

现在想给全类别设置别名标签typeAliases,结果发现报错了
标签顺序错误

MyBatis核心配置文件中的标签必须要按照指定顺序配置:
核心配置文件中configuration标签下的子标签要按照一定的顺序书写
● properties => settings => typeAliases => typeHandlers => >objectFactory =>
objectWrapperFactory => reflectorFactory => plugins => >environments =>
databaseIdProvider => mappers

下移 < typeAliases > 标签到< properties >下面

(4)核心配置文件中typeAliases起别名

    <!-- 给全类名设置别名,为某个具体的类型设置一个别名
         在MyBatis的范围中,可以使用别名
         type:设置需要起别名的类型:全类名
         alias:别名

     -->
    <typeAliases>
        <!-- 别名方式1 -->
        <!-- <typeAlias type="com.atguigu.mybatis.pojo.User" alias="User"></typeAlias>-->
        <!-- 别名方式2:默认是类名不需要区分大小写 -->
        <!--<typeAlias type="com.atguigu.mybatis.pojo.User"></typeAlias>-->
        <!-- 别名方式3:设置包名,包下的类都是别名 -->
        <package name="com.atguigu.mybatis.pojo"/>
    </typeAliases>

全类名别名
修改UserMapper.xml配置文件把别名替换上

    <select id="getUserById" resultType="User">
        select *
        from t_user
        where id = 1
    </select>

    <!-- List<User> getAllUser(); -->
    <select id="getAllUser" resultType="User">
        select *
        from t_user
    </select>

别名替代全类名
注意,用方式2定义别名,无需区分大小写

        <!-- 别名方式2:默认是类名不需要区分大小写 -->
        <typeAlias type="com.atguigu.mybatis.pojo.User"></typeAlias>

大小写都可以
方式3,直接给包定义,包下所有类都是别名

    <typeAliases>
        <!-- 别名方式3:设置包名,包下的类都是别名,且不区分大小写 -->
        <package name="com.atguigu.mybatis.pojo"/>
    </typeAliases>

pojo包起别名
方式3也是不区分大小写的

(5)核心配置文件mappers
    <!-- 引入MyBatis的映射文件 一张表对应一个映射文件的标签 -->
    <mappers>
        <!-- 方式1: -->
        <!--<mapper resource="mappers/UserMapper.xml"/>-->
        <!-- 方式2:以包的形式引入映射文件,但是需要满足以下2点
                   1.mapper接口和映射文件所在的包必须一致
                   2.mapper接口的名字和映射文件的名字必须一致
         -->
    </mappers>

创建目录
创建目录
目录名称:

com/atguigu/mybatis/mapper

移动UserMapper.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>
    <!-- MyBatis核心配置文件中的标签必须要按照指定顺序配置:
        核心配置文件中configuration标签下的子标签要按照一定的顺序书写
      ● properties => settings => typeAliases => typeHandlers => objectFactory =>
        objectWrapperFactory => reflectorFactory => plugins => environments =>
        databaseIdProvider => mappers
     -->

    <!-- 引入properties文件,此后可以在当前文件中使用${key}的形式访问value -->
    <properties resource="jdbc.properties"></properties>

    <!-- 给全类名设置别名,为某个具体的类型设置一个别名
         在MyBatis的范围中,可以使用别名
         type:设置需要起别名的类型:全类名
         alias:别名

     -->
    <typeAliases>
        <!-- 别名方式1 -->
        <!-- <typeAlias type="com.atguigu.mybatis.pojo.User" alias="User"></typeAlias>-->
        <!-- 别名方式2:默认是类名不需要区分大小写 -->
        <!--<typeAlias type="com.atguigu.mybatis.pojo.User"></typeAlias>-->
        <!-- 别名方式3:设置包名,包下的类都是别名,且不区分大小写 -->
        <package name="com.atguigu.mybatis.pojo"/>
    </typeAliases>

    <!-- 配置连接数据库的环境(多个) -->
    <!-- default指定具体使用哪个环境 -->
    <environments default="development">
        <!-- 开发环境 -->
        <!-- id:是环境的唯一标识不允许重复 -->
        <environment id="development">
            <!-- 事务的管理方式 事务管理器
                 type:JDBC  MANAGED
                 JDBC表示使用JDBC中原生的事务管理方式
                 MANAGED表示被管理的,例如spring整合MyBatis的时候,交给spring管理
             -->
            <transactionManager type="JDBC"/>
            <!-- dataSource数据源
                 type:设置数据源的类型
                 type: POOLED UNPOOLED JNDI
                 POOLED表示使用数据库连接池
                 UNPOOLED表示不适用数据库连接池
                 JNDI表示使用上下文中的数据源
             -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

        <!-- 测试环境 -->
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="hsp"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 引入MyBatis的映射文件 一张表对应一个映射文件的标签 -->
    <mappers>
        <!-- 方式1: -->
        <!--<mapper resource="mappers/UserMapper.xml"/>-->
        <!-- 方式2:以包的形式引入映射文件,但是需要满足以下2点
                   1.mapper接口和映射文件所在的包必须一致
                   2.mapper接口的名字和映射文件的名字必须一致
         -->
        <package name="com.atguigu.mybatis.mapper"/>
    </mappers>
</configuration>
(6)核心配置文件创建模板

核心配置文件创建模板配置一次,以后可以直接使用

<?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>
    <!-- MyBatis核心配置文件中的标签必须要按照指定顺序配置:
        核心配置文件中configuration标签下的子标签要按照一定的顺序书写
      ● properties => settings => typeAliases => typeHandlers => objectFactory =>
        objectWrapperFactory => reflectorFactory => plugins => environments =>
        databaseIdProvider => mappers
     -->

    <!-- 引入properties文件,此后可以在当前文件中使用${key}的形式访问value -->
    <properties resource="jdbc.properties"></properties>

    <!-- 给全类名设置别名,为某个具体的类型设置一个别名
         在MyBatis的范围中,可以使用别名
         type:设置需要起别名的类型:全类名
         alias:别名

     -->
    <typeAliases>
        <!-- 别名方式1 -->
        <!-- <typeAlias type="" alias="User"></typeAlias>-->
        <!-- 别名方式2:默认是类名不需要区分大小写 -->
        <!--<typeAlias type=""></typeAlias>-->
        <!-- 别名方式3:设置包名,包下的类都是别名,且不区分大小写 -->
        <package name=""/>
    </typeAliases>

    <!-- 配置连接数据库的环境(多个) -->
    <!-- default指定具体使用哪个环境 -->
    <environments default="development">
        <!-- 开发环境 -->
        <!-- id:是环境的唯一标识不允许重复 -->
        <environment id="development">
            <!-- 事务的管理方式 事务管理器
                 type:JDBC  MANAGED
                 JDBC表示使用JDBC中原生的事务管理方式
                 MANAGED表示被管理的,例如spring整合MyBatis的时候,交给spring管理
             -->
            <transactionManager type="JDBC"/>
            <!-- dataSource数据源
                 type:设置数据源的类型
                 type: POOLED UNPOOLED JNDI
                 POOLED表示使用数据库连接池
                 UNPOOLED表示不适用数据库连接池
                 JNDI表示使用上下文中的数据源
             -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

        <!-- 测试环境 -->
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="hsp"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 引入MyBatis的映射文件 一张表对应一个映射文件的标签 -->
    <mappers>
        <!-- 方式1: -->
        <!--<mapper resource=""/>-->
        <!-- 方式2:以包的形式引入映射文件,但是需要满足以下2点
                   1.mapper接口和映射文件所在的包必须一致
                   2.mapper接口的名字和映射文件的名字必须一致
         -->
        <package name=""/>
    </mappers>
</configuration>

模板名称:mybatis-config
创建模板文件

(7)Mapper配置文件模板
<?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="">
    <!--
        mapper接口和映射文件要保证两个一致
        1.mapper接口的权和类名和映射文件的namespace一致
        2.mapper接口中的方法的方法名要和映射文件中的sql的id保持一致
     -->

</mapper>

模板名称:mybatis-mapper
模板名称

(8)模板的使用

模板的使用

(9)使用模板搭建MyBatis框架

创建Module
创建Module
点击下一步
点击next
配置Maven信息
配置Maven信息

Name:mybatis-parameter
GroupId:com.atguigu.mybatis

 pom.xml直接拷贝上一个Module的即可

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SSM</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.mybatis</groupId>
    <artifactId>mybatis-parameter</artifactId>

    <!-- 打包方式 -->
    <packaging>jar</packaging>

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

    <dependencies>
        <!-- Mybatis核心 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.20</version>
        </dependency>
        <!-- log4j日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>

</project>

拷贝jdbc.properties和log4j.xml
拷贝配置文件
通过模板快速创建
模板创建

创建接口
com.atguigu.mybatis.mapper.UserMapper
注意选择接口
创建接口
创建文件夹
com/atguigu/mybatis/mapper

创建文件夹
模板创建mapper文件,名称要一致
模板创建mapper文件
配置全类名
配置全类名
拷贝User类即可
拷贝User类
核心配置文件配置相关路径

核心配置文件配置相关路径1
核心配置文件配置相关路径2

核心配置文件配置相关路径2

5.MyBatis获取参数值的两种方式

MyBatis获取参数值的两种方式:${}和#{}
> ${}的本质就是字符串拼接,
> #{}的本质就是占位符赋值。
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号。
所以 #{}可以避免sql注入
 

UserMapper中添加方法

    /**
     * @param
     * @return com.atguigu.mybatis.pojo.User
     * @description //通过用户名查询用户信息
     * @param: username
     * @date 2023/1/2 16:05
     * @author wty
     **/
    User getUserByUsername(String username);
5.1单个字面量类型的参数

若mapper接口中的方法参数为单个的字面量类型
此时可以使用 ${} 和 #{} 以任意的名称获取参数的值,
注意 ${} 需要手动加单引号
字面量:字符串、基本数据类型、基本数据类型对应的包装类 例如: int a = 1

#{}方式配置UserMapper.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.atguigu.mybatis.mapper.UserMapper">
    <!--
        mapper接口和映射文件要保证两个一致
        1.mapper接口的权和类名和映射文件的namespace一致
        2.mapper接口中的方法的方法名要和映射文件中的sql的id保持一致
     -->
    <!-- User getUserByUsername(String username); -->
    <select id="getUserByUsername" resultType="User">
        select *
        from t_user
        where username = #{username}
    </select>

</mapper>

创建测试类
com.atguigu.mybatis.parameterTest

创建测试类
拷贝工具类
拷贝工具类
编写测试类parameterTest

package com.atguigu.mybatis;

import com.atguigu.mybatis.mapper.UserMapper;
import com.atguigu.mybatis.pojo.User;
import com.atguigu.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

/**
 * @ClassName: parameterTest
 * @Description:
 * @Author: wty
 * @Date: 2023/1/2
 */

public class parameterTest {
    @Test
    public void getUserByUsername() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user = mapper.getUserByUsername("hsp");

        System.out.println(user);

        sqlSession.close();
    }
}

运行结果
运行结果
注意:
这里注意,大括号内可以为任意值,
因为底层Mapper配置文件不知道参数具体是哪个属性,但是起名最好要有意义
注意

紧接着继续修改UserMapper.xml,如果直接更改为${}

    <!-- User getUserByUsername(String username); -->
    <select id="getUserByUsername" resultType="User">
        <!--select *
        from t_user
        where username = #{username}-->
        select *
        from t_user
        where username = ${username}
    </select>

运行测试类会发现报错了
报错
所以要使用${}的时候要注意单引号的使用

    <!-- User getUserByUsername(String username); -->
    <select id="getUserByUsername" resultType="User">
        select *
        from t_user
        where username = '${username}'
    </select>

再次执行就没有错误了
增加单引号

5.2多个字面量类型的参数

若mapper接口中的方法参数为多个时
此时MyBatis会自动将这些参数放在一个map集合中,
(1)以arg0,arg1…为键,以参数为值;
(2)以param1,param2…为键,以参数为值;
因此只需要通过 ${} 和 #{} 访问map集合的键就可以获取相对应的值,
注意 ${} 需要手动加单引号

UserMapper.java增加方法

/**
     * @param
     * @return com.atguigu.mybatis.pojo.User
     * @description //验证用户名和密码
     * @param: username
     * @param: password
     * @date 2023/1/2 16:43
     * @author wty
     **/
    User checkLogin(String username, String password);

UserMapper.xml新增查询语句

    <!-- User checkLogin(String username, String password); -->
    <select id="checkLogin" resultType="User">
        select *
        from t_user
        where username = #{username}
          and password = #{password}
    </select>

编写测试类parameterTest

    @Test
    public void checkLogin() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user = mapper.checkLogin("hsp", "123");

        System.out.println(user);

        sqlSession.close();
    }

运行后发现报错
框架给出报错信息
发现框架给出了解决方案,那就按照解决方案配置UserMapper.xml

    <!-- User checkLogin(String username, String password); -->
    <select id="checkLogin" resultType="User">
        select *
        from t_user
        where username = #{arg0}
          and password = #{arg1}
    </select>

再次运行测试类发现运行成功
测试类
另一种框架给出的方案也试一试

    <!-- User checkLogin(String username, String password); -->
    <select id="checkLogin" resultType="User">
        select *
        from t_user
        where username = #{param1}
          and password = #{param2}
    </select>

发现也可以正常运行结果

尝试一下${}的方式

    <select id="checkLogin" resultType="User">
        select *
        from t_user
        where username = '${arg0}'
        and password = '${arg1}'
    </select>

以及

    <!-- User checkLogin(String username, String password); -->
    <select id="checkLogin" resultType="User">
        select *
        from t_user
        where username = '${param1}'
        and password = '${param2}'
    </select>

也没有问题,可以正常查询结果。

5.3map集合类型的参数

若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中只需要通过 ${} 和 #{} 访问map集合的键就可以获取相对应的值。
注意 ${} 需要手动加单引号

UserMapper.java添加方法

    /**
     * @param
     * @return com.atguigu.mybatis.pojo.User
     * @description //多条件查询
     * @param: map
     * @date 2023/1/2 17:16
     * @author wty
     **/
    User checkLoginMap(Map<String, Object> map);

UserMapper.xml添加查询

    <!-- User checkLoginMap(Map<String, Object> map) -->
    <select id="checkLoginMap" resultType="User">
        select *
        from t_user
        where username = #{username}
          and password = #{password}
    </select>

parameterTest.java添加测试类

 @Test
    public void checkLoginMap() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        HashMap<String, Object> map = new HashMap<>();
        map.put("username", "hsp");
        map.put("password", "123");
        User user = mapper.checkLoginMap(map);

        System.out.println(user);

        sqlSession.close();
    }

查询结果
查询结果

使用${}的方式

    <!-- User checkLoginMap(Map<String, Object> map) -->
    <select id="checkLoginMap" resultType="User">
        select *
        from t_user
        where username = '${username}'
        and password = '${password}'
    </select>

也可以正常运行

5.4实体类类型的参数

若mapper接口中的方法参数为实体类对象时
此时可以使用 ${} 和 #{} ,通过访问实体类对象中的属性名获取属性值,
注意 ${} 需要手动加单引号

UserMapper.java添加方法

    /**
     * @param
     * @return int
     * @description 添加用户信息
     * @param: user
     * @date 2023/1/2 17:29
     * @author wty
     **/
    int insertUser(User user);

UserMapper.xml添加语句

    <!-- int insertUser(User user); -->
    <insert id="insertUser">
        insert into t_user
        values (null,
                #{username},
                #{password},
                #{age},
                #{gender},
                #{email})
    </insert>

parameterTest.java测试类中增加方法

    @Test
    public void insertUserTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user = new User(null, "tony", "456", 24, "男", "tony@126.com");
        int i = mapper.insertUser(user);

        System.out.println("结果:" + i);

        sqlSession.close();
    }

执行结果
执行结果
换成${}的形式

   <!-- int insertUser(User user); -->
    <insert id="insertUser">
        insert into t_user
        values (null,
        '${username}',
        '${password}',
        '${age}',
        '${gender}',
        '${email}')
    </insert>

可以正常运行

5.5使用@Param标识参数

可以通过@Param注解标识mapper接口中的方法参数

此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以param1,param2…为键,以参数为值;只需要通过 ${} 和 #{} 访问map集合的键就可以获取相对应的值,
注意 ${} 需要手动加单引号

UserMapper.java添加方法

    /**
     * @param
     * @return com.atguigu.mybatis.pojo.User
     * @description //通过注解param来查询
     * @param: username
     * @param: password
     * @date 2023/1/3 15:51
     * @author wty
     **/
    User checkLoginByParam(@Param("username") String username, @Param("password") String password);


UserMapper.xml添加语句

    <!-- User checkLoginByParam(String username, String password); -->
    <select id="checkLoginByParam" resultType="User">
        select *
        from t_user
        where username = #{username}
          and password = #{password}
    </select>

parameterTest.java测试类中增加方法

    @Test
    public void checkLoginByParamTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user = mapper.checkLoginByParam("Linda", "234");

        System.out.println(user);

        sqlSession.close();
    }

查询结果
查询成功
将UserMapper.xml更改成${}

    <!-- User checkLoginByParam(String username, String password); -->
    <select id="checkLoginByParam" resultType="User">
        select *
        from t_user
        where username = '${username}'
        and password = '${password}'
    </select>

同样可以执行成功

将UserMapper.xml参数更改成param1和param2

    <!-- User checkLoginByParam(String username, String password); -->
    <select id="checkLoginByParam" resultType="User">
        select *
        from t_user
        where username = '${param1}'
        and password = '${param2}'
    </select>
  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿尔法波

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

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

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

打赏作者

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

抵扣说明:

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

余额充值