mybatis增删改查

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

增 删 改 的返回数据类型都是int

一、select查询

1、带参数查询

编写接口

com.lihaozhe.mapper.PersonMapper

参数只有一个时,@Param(“文件名”)可以不写,这是映射文件读取的文件名

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface PersonMapper {
    /**
     * 根据手机号查询用户信息
     * @param mobile
     * @return
     * 参数只有一个@Param("Mobile")可以不写,这是映射文件读取的文件名,生成映射文件
     */
    Person selectByMobile(@Param("mobile") String mobile);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。

<?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.lihaozhe.mapper.PersonMapper">

    <!--根据手机号查询用户信息-->
    <select id="selectByMobile" parameterType="java.lang.String" resultType="com.lihaozhe.pojo.Person">
        SELECT *
        FROM `person`
		WHERE `mobile` = #{mobile}
    </select>

</mapper>

这里映射配置文件里的sql语句读取到接口内的参数
在这里插入图片描述

测试类

com.lihaozhe.mapper.PersonMapperTest

注意:测试方法中获取SqlSession对象

@Test
public void selectByMobile(){
    // 获取该接口的代理对象
    PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
    // 执行接口中的方法
    Person person = mapper.selectByMobile("13925135946");
    // 释放SqlSession资源
    sqlSession.close();
    // 输出查询结果
    System.out.println(person);
}

2、#与$的区别

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。
这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。
比如 ORDER BY 子句,MyBatis 就不会修改或转义该字符串了。
#{} 会进行预编译,比较安全
${} 直译,获取值使直接

需求:查询的条件字段和该字段的值不确定时,需要通过查询字段在查询值

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface PersonMapper {
   /**
     * 根据不确定的字段查询
     * @param column 输入的参数是指字段名
     * @param value 输入的参数是指数据值
     * @return
     */
    Person selectByFiled(@Param("column") String column,@Param("value")String value);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml

这里注意
${}是直译,直接是参数值
#{}会预编译,编译完后有sql语句的参数有‘ 单引号 ’

<?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.lihaozhe.mapper.PersonMapper">

	<!--根据不确定的字段查询-->
    <select id="selectByFiled" resultType="com.lihaozhe.pojo.Person">
        SELECT *
        FROM `person`
        WHERE ${column} = #{value}
    </select>
</mapper>

测试

    @Test
    public void selectByFiled() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行接口中的方法
        Person person = mapper.selectByFiled("mobile","17778322703");
        // 释放SqlSession资源
        sqlSession.close();
        // 遍历集合
        System.out.println(person);
    }
}

在这里插入图片描述

3、别名映射

别名映射修改的是映射文件中类的的路径名
在核心配置文件中将类的路径名指定一个别名
有2种方法
1、为某个类指定别名
2、为某个包下的所有类指定别名 别名默认是这个类的首字母小写之后的字符串

起因:parameterType 和 resultType 的值 需要使用类的完全限定名 太麻烦 希望使用 简短的名字来替代 类的完全限定名

在核心配置文件中 配置如下内容:

<typeAliases>
    <!--
		别名
		type	类的完全限定名
		alias	别名
    -->
    <!--1、为某个类指定别名-->
    <!--<typeAlias alias="login" type="com.lihaozhe.pojo.Login"/>-->
    <!--2、为某个包下的所有类指定别名 别名默认为类的首字母小写之后的字符串-->
    <package name="com.lihaozhe.pojo"/>
</typeAliases>

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 上午8:52
 */
public interface PersonMapper {
    /**
     * 根据唯一身份标识符用户信息
     *
     * @param uuid
     * @return
     */
    Person selectByUuid(@Param("uuid") String uuid);;
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.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.lihaozhe.mapper.PersonMapper">
    <!--根据唯一身份标识符用户信息-->
    <select id="selectByUuid" resultType="person">
        SELECT *
        FROM `person`
        WHERE uuid = #{uuid}
    </select>
</mapper>

测试类

com.lihaozhe.mapper.PersonMapperTest

注意:测试方法中获取SqlSession对象

 @Test
    public void selectByuuid() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行接口中的方法
        Person person = mapper.selectByuuid("uuid","2b6e912a2e56485ea4233eca400c38ab");
        // 释放SqlSession资源
        sqlSession.close();
        // 遍历集合
        System.out.println(person);
    }

完整核心配置文件

src/main/resources/mybatis/myatis-confog.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>
    <!--
        这些属性可以在外部进行配置,并可以进行动态替换。
        你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置
    -->
    <properties resource="config.properties" />
    <settings>
        <!-- 驼峰命名与下划线自动转换 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- log日志 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
        <!--
            别名
            type	类的完全限定名
            alias	别名
        -->
        <!--为某个类指定别名-->
        <!--<typeAlias alias="person" type="com.lihaozhe.pojo.Person"/>-->
        <!--为某个包下的所有类指定别名 别名默认为类的首字母小写之后的字符串-->
        <package name="com.lihaozhe.pojo"/>
    </typeAliases>
    <!--
        MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。
        例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
    -->
    <!--默认使用的环境 ID(比如:default="development")。-->
    <environments default="development">
        <!--每个 environment 元素定义的环境 ID(比如:id="development")。-->
        <environment id="development">
            <!--事务管理器的配置(比如:type="JDBC")。-->
            <!--
                事务管理器(transactionManager)
                在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
                JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
                MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。
                默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
                如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
                这两种事务管理器类型都不需要设置任何属性。它们其实是类型别名,换句话说,你可以用 TransactionFactory 接口实现类的全限定名或类型别名代替它们。
            -->
            <transactionManager type="JDBC"/>
            <!--数据源的配置(比如:type="POOLED")-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>

    </environments>
    <mappers>
        <!-- 使用相对于类路径的资源引用 -->
        <!--单独加载某个映射配置文件-->
        <!--<mapper resource="mybatis/mapper/PersonMapper.xml"/>-->
        <!-- 使用完全限定资源定位符(URL) -->
        <!--<mapper url="file:///home/lhz/mybatis/src/main/resources/com/lihaozhe/mapper/PersonMapper.xml"/>-->
        <!--<mapper url="file:///D:/mybatis/src/main/resources/com/lihaozhe/mapper/PersonMapper.xml"/>-->
        <!--加载某包下所有的映射配置文件-->
        <package name="com.lihaozhe.mapper"/>
    </mappers>

</configuration>

二、insert新增

首先生成pojo类,封装,构造方法

编写接口

com.lihaozhe.mapper.DeptMapper
增删改的返回值都是int类型,是行数的变动

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface DeptMapper {
    /**
     * 新增部门
     *
     * @param dept
     * @return
     */
    int insert(@Param("dept") Dept dept);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/DeptMapper.xml

新增数据中的新增占位 #{dept.dname}是指 某表下的字段

<?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.lihaozhe.mapper.DeptMapper">
    <!--新增部门-->
    <insert id="insert">
        INSERT INTO `dept` (`dname`)
        VALUES (#{dept.dname})
    </insert>
</mapper>

测试类

com.lihaozhe.mapper.DeptMapperTest

注意:测试方法中获取SqlSession对象

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public class DeptMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }
    @Test
    public void insert(){
        // 获取代理对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        // 准备数据
        Dept dept = new Dept("人事部");
        // 插入之前 输出准备数据
        System.out.println("插入之前 dept >>> " + dept);
        // 调用方法执行 insert 操作
        mapper.insert(dept);
        // 手动提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
        // 插入之后 输出准备数据
        System.out.println("插入之后 dept >>> " + dept);
    }
}

新增数据主键并没有自增需要在映射文件中配置

解析结果:
插入之前 dept >>> Dept(did=0, dname=人事部)
Opening JDBC Connection
Created connection 671596011.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
==>  Preparing: INSERT INTO `dept` (`dname`) VALUES (?)
==> Parameters: 人事部(String)
<==    Updates: 1
Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Returned connection 671596011 to pool.
插入之后 dept >>> Dept(did=0, dname=人事部)

新增数据后如何获取新增数据主键值

新增时,需要自己指定主键 自增

<?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.lihaozhe.mapper.DeptMapper">
    <!--新增部门-->
    <!--
        useGeneratedKeys参数默认是false,
        在进行insert操作后是获取不到自增的id的,
        如果我们需要用到主键需要将参数值改为true
        keyProperty javabean 中主键 filed
        keyColumn datatable 中主键 filed
    -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="did" keyColumn="did">
        INSERT INTO `dept` (`dname`)
        VALUES (#{dept.dname})
    </insert>
</mapper>

三、update修改

编写接口

com.lihaozhe.mapper.DeptMappe

根据部门主键修改,传一个值返回一个对象

package com.lihaozhe.mapper;

import cn.hutool.core.collection.LineIter;
import com.lihaozhe.pojo.Dept;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface DeptMapper {

    /**
     * 修改部门信息
     *
     * @param dept
     * @return
     */
    int update(@Param("dept") Dept dept);

}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/DeptMapper.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.lihaozhe.mapper.DeptMapper">
    <!--修改部门信息  dname中是要更新的部门,条件是did 传入一个表的id-->
    <update id="update">
        UPDATE `dept`
        SET `dname` = #{dept.dname}
        WHERE `did` = #{dept.did}
    </update>
</mapper>

测试类

com.lihaozhe.mapper.DeptMappeTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public class DeptMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void getSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }
    @Test
    public void update() {
        // 获取代理对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        // 准备数据
        Dept dept = new Dept(8, "企宣部");
        // 调用方法执行 update 操作
        mapper.update(dept);
        // 手动提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
}

四、delete删除

编写接口

com.lihaozhe.mapper.DeptMappe

根据部门主键删除,传一个id完成删除所以是long基本类型

package com.lihaozhe.mapper;

import cn.hutool.core.collection.LineIter;
import com.lihaozhe.pojo.Dept;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午11:13
 */
public interface DeptMapper {

    /**
     * 根据部门id删除部门
     *
     * @param did
     * @return
     */
    int deleteByDid(@Param("did") long did);

}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/DeptMapper.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.lihaozhe.mapper.DeptMapper">
   <!--根据部门id删除部门-->
   <delete id="deleteByDid">
        DELETE
        FROM `dept`
        WHERE `did` = #{did}
    </delete>
</mapper>

测试类

com.lihaozhe.mapper.DeptMappeTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:56
 */
public class DeptMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void getSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void deleteByDid(){
        // 获取代理对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        // 调用方法执行 delete 操作
        mapper.deleteByDid(8);
        // 手动提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
}

五、工具类

com.lihaozhe.util.mybatis.MyBatisUtil

package com.lihaozhe.util.mybatis;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ExecutorType;
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.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/13 上午11:39
 */
public abstract class MyBatisUtil {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    private static SqlSessionFactory sqlSessionFactory;
    private static SqlSession sqlSession;

    static {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(resource);
            // 构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 获取 SqlSession 对象
     *
     * @return SqlSession 对象
     */
    public static SqlSession openSqlSession() {
        if (threadLocal.get() == null) {
            // 从SqlSessionFactory对象中获取SqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 与线程绑定
            threadLocal.set(sqlSession);
            // 返回 SqlSession 对象
            return sqlSession;
        } else {
            return threadLocal.get();
        }
    }

    /**
     * 获取 SqlSession 对象
     *
     * @param executorType SIMPLE,REUSE,BATCH
     * @return SqlSession 对象
     */
    public static SqlSession openSqlSession(ExecutorType executorType) {
        if (threadLocal.get() == null) {
            // 从SqlSessionFactory对象中获取SqlSession
            sqlSession = sqlSessionFactory.openSession(executorType);
            // 与线程绑定
            threadLocal.set(sqlSession);
            // 返回 SqlSession 对象
            return sqlSession;
        } else {
            return threadLocal.get();
        }
    }

    /**
     * 释放资源
     */
    public static void close() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.close();
        }
    }

    /**
     * 事务提交 释放资源
     */
    public static void commitAndClose() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.commit();
            sqlSession.close();
        }
    }

    /**
     * 事务回滚 释放资源
     */
    public static void rollbackAndClose() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.rollback();
            sqlSession.close();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值