mybatis对数据库的增删改查

270 阅读9分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

Mybatis对数据库操作的优势

JAVA编程免不了和数据库打交道,那么如何高效便捷地操作数据库,也是一个需要应对的问题,原生的基于JDBC的方式非常低效,而且要写一大堆无用的模板代码,不值得选取。ORM是对JDBC的封装,让我们不需要重复的造轮子,目前已经有很多优秀的ORM框架可供使用了,常见的比如Mybatis(batis)、Hibernate、Jpa、Jdo等。

优点:

  • ORM是对JDBC的封装,从而解决了JDBC的各种存在问题,提高效率
  • 使开发更加对象化
  • 可移植性强
  • 可以很方便地引入数据缓存之类的附加功能

缺点:

  • 自动化进行关系数据库的映射需要消耗少量系统性能。
  • 在处理多表联查、where条件复杂之类的查询时,ORM的语法会变得复杂。

市面上主流ORM框架:

  • EJB:重量级、高花费的ORM技术,支持JPA,尤其是EJB3低侵入式 的设·计,增加了Annotation
  • Hibernate:开源,支持JPA ,被选作JBoss的持久层解决方案
  • iBatis:”SQL Mapping”框架,Apache软件基金组织的子项目,后 转Google Code旗下,ibatis3.x正式更名为Mybatis
  • Spring Data JPA:Spring框架中的子模块
  • TopLink:Oracle公司的产品
  • Open JPA:Apache软件基金组织的开源项目

Mybatis都有哪些优势?

  • Mybatis入门简单;在使用上,对于熟悉编写SQL的同学来说,基本上是即学即用。
  • Mybatis对jdbc的抽象封装程度更高,spring jdbc要想实现的细节很多,例如Mybatis封装了更多的对象映射。
  • 支持注解,面对接口开发,效率高,分分钟解决一个sql。
  • 对于复杂的SQL,springJDBC编写麻烦,动态SQL语句设计也麻烦,相比之下,Mybatis更加灵活且人性化。
  • mybatis的高度封装,使得程序员可专注与业务层,开发效率高。所以选择mybatis的开发公司多。

相比较Hibernate与Mybatis的区别?

Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。

Hibernate和MyBatis都支持JDBC和JTA事务处理。

Mybatis优势

  • MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
  • MyBatis容易掌握,而Hibernate门槛较高。

Hibernate优势

  • Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
  • Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
  • Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
  • Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

Hibernate

  • Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。
  • Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。

MyBatis

  • MyBatis入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
  • MyBatis的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

Hibernate与Mybatis 的缓存机制都有哪些区别?

相同点:

Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。

不同点:

Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。

MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。

下面通过对数据的增删改查来看出mybatis的优势

1.mybatis对数据库的增删改查

数据库的建立和User实体类的创建

package com.mybatisD.domain;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

图片.png

配置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.mybatisD.dao.IUserDao">
    <!--配置查询所有-->
    <select id="findAll" resultType="com.mybatisD.domain.User">
        select * from user
    </select>
    <!--保存用户-->
    <insert id="saveUser" parameterType="com.mybatisD.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.mybatisD.domain.User">
        update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
    </update>
    <!--删除用户-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id=#{userid}
    </delete>
    <!--根据ID查询用户-->
    <select id="findById" parameterType="INT" resultType="com.mybatisD.domain.User">
        select * from user where id=#{userid}
    </select>
    <!--更具名称模糊查寻-->
    <select id="findByName" parameterType="string" resultType="com.mybatisD.domain.User">
        select * from user where username like #{name}
    </select>
    <!--获取用户总计录-->
    <select id="findTotal" resultType="int">
        select count(id) from user
    </select>

    <!--更具QueryVo的条件查询用户使用OJN表达式-->
    <select id="findUserByVo" parameterType="com.mybatisD.domain.QueryVo" resultType="com.mybatisD.domain.User">
        select * from USER  where username like #{user.username}
    </select>
</mapper>

配置SqlMapConfig.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>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql环境-->
        <environment id="mysql">
            <!--配置事物类型-->
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <!--配置连接数据库的4个信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/newsql?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
    <!--指定映射配置文件的位置,映射配置文件指的是每个到独立的配置文件-->
    <mappers>
        <mapper resource="com/mybatisD/dao/IUserDao.xml"/>
    </mappers>
    <!--如果要是用注解来配置的话,此处应该使用class属性指定被注解的dao全限定类名-->
    <!--<mappers>
        <mapper class="com.mybatisD.dao.IUserDao"/>
    </mappers>-->
</configuration>

创建log4j.properties日志

log4j.rootCategory=debug,CONSOLE, LOGFILE
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x -%m\n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x -%m\n

创建测试类test

package com.mybatisJ.test;



import com.mybatisD.dao.IUserDao;
import com.mybatisD.domain.QueryVo;
import com.mybatisD.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;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-20 21:55
 */
public class MybatisTest {
   private InputStream in;
   private SqlSession sqlSession;
   private IUserDao userDao;

   @Before//用于在测试方法执行之前执行
    public void init()throws  Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
       sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }
    @After//用于在测试方法之后执行
    public void destory() throws Exception{
        //添加提交事物,不添加无法提交
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }
    @Test
    public  void testFindAll() throws  Exception{

        List<User> users = userDao.findAll();
        for (User user: users) {
            System.out.println(user);
        }
    }
    //添加用户对象
    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("测试用户对象");
        user.setAddress("湖南");
        user.setSex("男");
        user.setBirthday(new Date());
        //执行保存方法
        userDao.saveUser(user);
        System.out.println(user);
    }
    //更新操作
    @Test
    public void testupdateUser(){
        User user = new User();
        user.setId(5);
        user.setUsername("更新测试用户");
        user.setAddress("北京");
        user.setSex("女");
        user.setBirthday(new Date());
        //执行保存方法
        userDao.updateUser(user);
    }

    //执行删除方法
    @Test
    public void testdeleteUser(){
        userDao.deleteUser(6);
    }
    //执行查询一个用户的方法
    @Test
    public void testFindOne(){
       User user = userDao.findById(5);
        System.out.println(user);
    }
    //执行名称的模糊查询
    @Test
    public void testFindByName(){
        List<User> user= userDao.findByName("%王%");
        System.out.println(user);
    }
    //执行查询总数
    @Test
    public void testFindTotal(){
        int count = userDao.findTotal();
        System.out.println(count);
    }

    //测试使用Query作为查询条件
    @Test
    public void testFindByVo(){
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUsername("%王%");
        vo.setUser(user);
        List<User> users = userDao.findUserByVo(vo);
        for (User u: users) {
            System.out.println(u);
        }
    }

}

其中的一处测试涉及到一个实现类QueryVo

package com.mybatisD.domain;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-21 16:05
 */
public class QueryVo {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

Maven的pom.xml配置导入依赖

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.myBatisDemo</groupId>
    <artifactId>MyBatis_Demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--打包方式-->
    <packaging>jar</packaging>
    <!--db-->
    <!--基本的maven配置就完成了 现在添加使用Mybatis的基本配置-->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>

        <!--其他的基本配置,日志、单元测试、jdbc——jar包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!--<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.12</version>
        </dependency>-->
        <!--<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>

    <!--配置编译源代码的jdk版本-->
   <!-- <build>-->
       <!-- <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>-->
     <!--   <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**.*.xml</include>
                </includes>
            </resource>
        </resources>-->
 <!--   </build>-->
</project>

其中注意:java中与MySQL里面的各个字段不对应时可以进行下面的操作

 <!--配置查询结果的列名和实体类的属性名的对应关系-->
    <resultMap id="userMap" type="com.mybatisD.domain.User">
        <!--主键字段的对应-->
        <id property="userId" column="id"></id>
        <!--非主键字段的对应-->
        <result property="userName" column="username"></result>
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
    </resultMap>

也可以单独进行实现其中dao的方法如创建实现类UserDaoImpl

package com.mybatisD.dao.impl;

import com.mybatisD.dao.IUserDao;
import com.mybatisD.domain.QueryVo;
import com.mybatisD.domain.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-21 16:49
 */
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.mybatisD.dao.IUserDao.findAll");
        //3.释放资源
        session.close();
        return users;
    }

    public void saveUser(User user) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现保存
        session.insert("com.mybatisD.dao.IUserDao.saveUser",user);
        //3.提交事物
        session.commit();
        //4.释放资源
        session.close();
    }

    public void updateUser(User user) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现保存
        session.update("com.mybatisD.dao.IUserDao.updateUser",user);
        //3.提交事物
        session.commit();
        //4.释放资源
        session.close();
    }

    public void deleteUser(Integer userId) {
//1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现保存
        session.update("com.mybatisD.dao.IUserDao.deleteUser",userId);
        //3.提交事物
        session.commit();
        //4.释放资源
        session.close();
    }

    public User findById(Integer userId) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        User users = session.selectOne("com.mybatisD.dao.IUserDao.findById",userId);
        //3.释放资源
        session.close();
        return users;
    }

    public List<User> findByName(String username) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("com.mybatisD.dao.IUserDao.findByName",username);//参数就是获取配置信息的key
        //3.释放资源
        session.close();
        return users;
    }

    public int findTotal() {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        Integer  count = session.selectOne("com.mybatisD.dao.IUserDao.findTotal");
        //3.释放资源
        session.close();
        return count;
    }

    public List<User> findUserByVo(QueryVo vo) {
        return null;
    }
}

其中的测试类就需要进行一下改变,其它的配置不变

package com.mybatisJ.test;



import com.mybatisD.dao.IUserDao;
import com.mybatisD.dao.impl.UserDaoImpl;
import com.mybatisD.domain.QueryVo;
import com.mybatisD.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;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-20 21:55
 */
public class MybatisTest {
   private InputStream in;
   private IUserDao userDao;

   @Before//用于在测试方法执行之前执行
    public void init()throws  Exception{
       //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //2.获取SqlSessionFactory
        SqlSessionFactory factory = builder.build(in);
       //3.使用工厂对象,创建dao对象
        userDao = new UserDaoImpl(factory);
    }
    @After//用于在测试方法之后执行
    public void destory() throws Exception{
        //添加提交事物,不添加无法提交

        in.close();
    }
    @Test
    public  void testFindAll() throws  Exception{

        List<User> users = userDao.findAll();
        for (User user: users) {
            System.out.println(user);
        }
    }

    //添加用户对象
    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("测试用户对象");
        user.setAddress("湖南");
        user.setSex("男");
        user.setBirthday(new Date());
        //执行保存方法
        userDao.saveUser(user);
        System.out.println(user);
    }

    //更新操作
    @Test
    public void testupdateUser(){
        User user = new User();
        user.setId(7);
        user.setUsername("更新测试用户");
        user.setAddress("北京");
        user.setSex("女");
        user.setBirthday(new Date());
        //执行保存方法
        userDao.updateUser(user);
    }

    //执行删除方法
    @Test
    public void testdeleteUser(){
        userDao.deleteUser(8);
    }

    //执行查询一个用户的方法
    @Test
    public void testFindOne(){
       User user = userDao.findById(5);
        System.out.println(user);
    }

    //执行名称的模糊查询
    @Test
    public void testFindByName(){
        List<User> user= userDao.findByName("%王%");
        System.out.println(user);
    }

    //执行查询总数
    @Test
    public void testFindTotal(){
        int count = userDao.findTotal();
        System.out.println(count);
    }

}

对外部配置数据库信息jdbcConfig.properties的引入

<?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>
    <!--配置properties文件 可以在标签内部配置数据库的信息,也可以通过属性引用外部配置信息
    resource属性:用于指定配置文件的位置,是按照类路径的写法来写平且必须存在与类路径下
    -->
    <properties resource="jdbcConfig.properties">

        <!--<property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/newsql?characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value=""/>-->

    </properties>


    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql环境-->
        <environment id="mysql">
            <!--配置事物类型-->
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <!--配置连接数据库的4个信息-->
                <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>
    </environments>
    <!--指定映射配置文件的位置,映射配置文件指的是每个到独立的配置文件-->
    <mappers>
        <mapper resource="com/mybatisD/dao/IUserDao.xml"/>
    </mappers>
    <!--如果要是用注解来配置的话,此处应该使用class属性指定被注解的dao全限定类名-->
    <!--<mappers>
        <mapper class="com.mybatisD.dao.IUserDao"/>
    </mappers>-->
</configuration>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/newsql?characterEncoding=utf-8
jdbc.username=root
jdbc.password=

其中url属性的描述:uniform Resource Locator 统一资源定位符,它是可以唯一标识一个资源的位置 它的写法:http://ip:port/资源路径/jdbcConfig.properties

URI:uniform Resource Identifier 统一资源标识符,它是在应用中可以唯一定位一个资源 file:路径 或者 文件路径 标签typeAliases:可以起别名

 <!--使用typeAlias配置别名,它只能配置domain类中的别名-->
    <typeAliases>
        <!--typeAliases用于配置别名,type属性指定的是实体类全限定类名,alias属性指定别名,当指定了别名就再区分大小写-->
        <typeAlias type="com.mybatisD.domain.User" alias="user"></typeAlias>
        <!--用于指定配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
        <package name="com.mybatisD.domain"/>
    </typeAliases>


 <mappers>
        <!--package标签用于指定doa接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了-->
        <package name="com.mybatisD.domain"/>
    </mappers>

2.还有什么问题可以留言给我,会尽心解答的,觉得文章不错的话点个赞把