首页 > 编程语言 > 详细

SpringBoot:整合Druid、MyBatis

时间:2020-04-19 11:28:28      阅读:46      评论:0      收藏:0      [点我收藏+]

SpringBoot 整合Druid、MyBatis

简介

对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。

Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。

Sping Data 官网

数据库相关的启动器 : 可以参考官方文档

JDBC

导入依赖

<!--jdbc-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--web-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

连接数据库

首先我们需要连接数据库,我们直接使用IDEA连接即可

在SpringBoot中,我们需要连接数据库,只需要简单的配置即可

在 application.yaml 中:

spring:
  datasource:
    username: root
    password: root
    # serverTimezone=UTC:MySQL 8+以上使用
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=ture&characterEncoding=UTF-8&serverTimezone=UTC
     # mysql 8+以上使用  
    driver-class-name: com.mysql.cj.jdbc.Driver    

技术分享图片

配置完这一些东西后,我们就可以直接去使用了,因为SpringBoot已经默认帮我们进行了自动配置;我们去测试类测试一下

@SpringBootTest
class Springboot03DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下默认的数据源
        System.out.println(dataSource.getClass());
        System.out.println("==========");
				// 获得连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        // 归还连接
        connection.close();
    }
}

输出结果:

class com.zaxxer.hikari.HikariDataSource

2020-02-24 16:46:56.963  INFO 19388 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-02-24 16:46:59.953  INFO 19388 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
HikariProxyConnection@1336418989 wrapping com.mysql.cj.jdbc.ConnectionImpl@597f0937

从输出结果中可以看出,SpringBoot默认的数据源是:com.zaxxer.hikari.HikariDataSource,我们并没有手动配置。

Spring Boot 2.1.7 默认使用 com.zaxxer.hikari.HikariDataSource 数据源,而以前版本,如 Spring Boot 1.5 默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源;

HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀;

CRUD操作

  1. 有了数据源(com.zaxxer.hikari.HikariDataSource),就可以拿到数据库连接(java.sql.Connection),有了连接,就可以使用原生的 JDBC 语句来操作数据库。
  2. 即使不使用第三方的数据库操作框架,如MyBatis等,Spring 本身也对原生的 JDBC 做了轻量级的封装,即:org.springframework.jdbc.core.JdbcTemplate
  3. 数据库操作的所有 CRUD 方法都在 JdbcTemplate 中。
  4. Spring Boot 不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中,程序员只需自己注入即可使用
  5. JdbcTemplate 的自动配置原理是依赖 org.springframework.boot.autoconfigure.jdbc 包下的 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration

JdbcTemplate主要提供以下几类方法:

  • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
  • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
  • query方法及queryForXXX方法:用于执行查询相关语句;
  • call方法:用于执行存储过程、函数相关语句。

测试:

@RestController
public class JdbcController {
    // JdbcTemplate 是 core 包的核心类,用于简化 JDBC操作,还能避免一些常见的错误,如忘记关闭数据库连接
    // Spring Boot 默认提供了数据源,默认提供了 org.springframework.jdbc.core.JdbcTemplate
    // JdbcTemplate 中会自己注入数据源,使用起来也不用再自己来关闭数据库连接
    @Autowired
    JdbcTemplate jdbcTemplate;

    @GetMapping("/userList")
    public List<Map<String, Object>> userList() {

        String sql = "select id, name, pwd from mybatis.user";

        List<Map<String, Object>> list_maps = jdbcTemplate.queryForList(sql);

        return list_maps;
    }


    @GetMapping("/updUser/{id}")
    public String updateUser(@PathVariable("id") Integer id) {
        String sql = "update mybatis.user set name = ?, pwd = ? where id = " + id;

        // 数据
        Object[] objects = new Object[2];
        objects[0] = "王五";
        objects[1] = "helloworld";

        jdbcTemplate.update(sql, objects);

        return "update-ok";
    }

    @GetMapping("/delUser/{id}")
    public String deleteUser(@PathVariable("id") Integer id) {
        String sql = "delete from mybatis.user where id = ?";

        jdbcTemplate.update(sql, id);
        return "delete-ok";
    }

    @GetMapping("/addUser")
    public String addUser() {
        String sql = "insert into mybatis.user (name, pwd) values (?, ?)";

        // 数据
        Object[] objects = new Object[2];
        objects[0] = "李华";
        objects[1] = "123klajfld";

        jdbcTemplate.update(sql, objects);

        return "insert-ok";
    }
}

原理探究:

org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration 数据源配置类作用 :根据逻辑判断之后,添加数据源;

DataSourceConfiguration DataSourceAutoConfiguration 实际导入的数据源配置类。

tomcat的jdbc连接池:

技术分享图片

Hikari:

技术分享图片

dbcp2:

技术分享图片

自定义数据源:

技术分享图片

因为SpringBoot 2.x 默认数据源是:com.zaxxer.hikari.HikariDataSource,而其他我们没有导入相应的类,所有会爆红!

SpringBoot默认支持以下数据源:

  • com.zaxxer.hikari.HikariDataSource (Spring Boot 2.0 以上,默认使用此数据源)

  • org.apache.tomcat.jdbc.pool.DataSource

  • org.apache.commons.dbcp2.BasicDataSource

可以使用 spring.datasource.type 指定自定义的数据源类型,值为 要使用的连接池实现的完全限定名。默认情况下,它是从类路径自动检测的。

/**
 * 通用数据源配置
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {

   @Bean
   DataSource dataSource(DataSourceProperties properties) {
      return properties.initializeDataSourceBuilder().build();
   }

}

自定义数据源 DruidDataSource

Druid 简介

Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP、PROXOOL 等 DB 池的优点,同时加入了日志监控。

Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。

Spring Boot 2.0 以上默认使用 Hikari 数据源,可以说 Hikari 与 Driud 都是当前 Java Web 上最优秀的数据源,我们来重点介绍 Spring Boot 如何集成 Druid 数据源,如何实现数据库监控。

Druid 的GitHub官网

配置数据源

Druid依赖:

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.12</version>
</dependency>

现在我们去切换数据源;

之前已经说过 SpringBoot 2.0以上默认使用 com.zaxxer.hikari.HikariDataSource 数据源,但可以通过 spring.datasource.type 指定数据源

技术分享图片

数据源切换之后,同理可以注入 DataSource,测试类不用变,一测便知!

技术分享图片

Druid数据库连接池可以配置一些参数:

spring:
  datasource:
    username: root
    password: root
    # serverTimezone=UTC:MySQL 8+以上使用
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=ture&characterEncoding=UTF-8&serverTimezone=UTC
    # mysql 8+以上使用
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 切换数据源
    type: org.springframework.jdbc.datasource.DriverManagerDataSource

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

log4j日志依赖

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

现在需要程序员自己为 com.alibaba.druid.pool.DruidDataSource 绑定到全局配置文件中的参数,再添加到容器中,而不再使用 Spring Boot 的自动生成了;

我们需要 自己添加 DruidDataSource 组件到容器中,并绑定属性;

package com.rainszj.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DruidConfig {

    /*
    将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
    绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
    @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
    前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {

        return new DruidDataSource();
    }

}

去测试类中测试一下;看是否成功!

@SpringBootTest
class Springboot03DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下驱动类
        System.out.println(dataSource.getClass());
        System.out.println("==========");

        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        DruidDataSource druidDataSource = (DruidDataSource) this.dataSource;

        System.out.println("最大连接数为:" + druidDataSource.getMaxActive());

        System.out.println("数据源初始化连接数:" + druidDataSource.getInitialSize());

        // 归还连接
        connection.close();
    }
}

打印结果:

技术分享图片

配置 Druid 数据源监控

Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的 web 页面。

所以第一步需要设置 Druid 的后台管理页面,比如 登录账号、密码 等;配置后台管理

需要在 DruidConfig 中配置如下内容:

// 配置 Druid 监控管理后台的Servlet;
// 内置 Servler 容器时没有web.xml文件,所以使用 SpringBoot的注册 Servlet 方式
@Bean
public ServletRegistrationBean statViewServlet() {
  			// 创建Servlet注册实体
  			// /druid/*:后台访问的路径
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        Map<String, String> initParams = new HashMap<>();
        initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
        initParams.put("loginPassword", "123456"); //后台管理界面的登录密码

        //后台允许谁可以访问
        //initParams.put("allow", ""127.0.0.1""):表示只有本机可以访问
        //initParams.put("allow", ""):为空或者为null时,表示允许所有访问
        initParams.put("allow", "");
        //deny:Druid 后台拒绝谁访问
        //initParams.put("deny", "192.168.1.20");表示禁止此ip访问

        //设置初始化参数
        bean.setInitParameters(initParams);
        return bean;
    }

这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到

技术分享图片

配置完毕后,我们可以选择访问 : http://localhost:8080/druid/login.html

登录界面:

技术分享图片

首页:

技术分享图片

配置 Druid web 监控 filter

这个过滤器的作用就是统计 web 应用请求中所有的数据库信息,比如 发出的 sql 语句,sql 执行的时间、请求次数、请求的 url 地址、以及seesion 监控、数据库表的访问次数 等等

需要在 DruidConfig 中配置如下内容:

//配置 Druid 监控 之  web 监控的 filter
//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
@Bean
public FilterRegistrationBean filterRegistrationBean() {

    FilterRegistrationBean bean = new FilterRegistrationBean(new WebStatFilter());

    // 设置过滤器的过滤路径
    bean.addUrlPatterns("/*");
    // bean.setUrlPatterns(Arrays.asList("/*"));

    Map<String, String> initParameters = new HashMap<String, String>();
    // 过滤这些东西不进行统计
    initParameters.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");

    bean.setInitParameters(initParameters);

    return bean;
}

这些参数在 WebStatFilter类中

技术分享图片

整合MyBatis

Maven仓库

技术分享图片

版本要求:

技术分享图片

第一步:导入Spring Boot 整合 MyBatis的 依赖:

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

<!--mysql驱动-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>

<!--jdbc-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

第二步:配置数据库连接信息

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver

加载类 com.mysql.jdbc.Driver。不推荐使用。新的驱动程序类为 com.mysql.cj.jdbc.Driver。通过SPI自动注册驱动程序,通常不需要手动加载驱动程序类。

这里使用默认的数据源,测试数据库连接是否成功:

@SpringBootTest
class Springboot03DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下驱动类
        System.out.println(dataSource.getClass());
        System.out.println("==========");

        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        System.out.println(connection.getMetaData().getURL());

        // 归还连接
        connection.close();
    }
}

连接成功,OK!

技术分享图片

第三步:创建实体类:

package com.rainszj.pojo;


public class User {

    private int id;
    private String name;
    private String pwd;


    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name=‘" + name + ‘\‘‘ +
                ", pwd=‘" + pwd + ‘\‘‘ +
                ‘}‘;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

第四步:配置Mapper接口,也就是dao层:

package com.rainszj.mapper;

import com.rainszj.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;


/**
 * @Mapper:标记这个类是MyBatis的Mapper,等价于Spring整合MyBatis时的Mapper接口
 */
@Mapper
/**
 * @Rpository:将这个接口添加进Spring容器中,和 @Component等价
 */
@Repository
public interface UserMapper {

    // 查询所有用户
    List<User> selectAllUsers();

    // 根据id查找用户
    User findUserById(@Param("uid")Integer id);

    // 修改用户
    int updateUser(User user);

    // 添加用户
    int addUser(User user);

    // 删除用户
    int deleteUser(Integer id);

}

第五步:在application.yaml中添加MyBatis的配置

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver

# 整合MyBatis
mybatis:
  # 配置别名
  type-aliases-package: com.rainszj.pojo
  # 绑定Mapper配置文件
  # 注意:这里的 classpath代指:resources目录
  mapper-locations: classpath:mybatis/mapper/*.xml

技术分享图片

spring boot 官方并没有提供 myBaits 的启动器,是 myBatis 官方提供的开发包来适配的 spring boot,从 pom.xml 文件中的依赖包名也能看出来,并非是以 spring-boot 开头的;

同理上面全局配置文件中的这两行配置也是以 mybatis 开头 而非 spring 开头也充分说明这些都是 myBatis 官方提供的

可以从 org.mybatis.spring.boot.autoconfigure.MybatisProperties 中查看所有配置项

也可以看:mybatis-spring-boot官网

/**
 * Configuration properties for MyBatis.
 *
 * @author Eddú Meléndez
 * @author Kazuki Shimizu
 */
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {

  public static final String MYBATIS_PREFIX = "mybatis";

  private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();

  /**
   * Location of MyBatis xml config file.
   */
  private String configLocation;

  /**
   * Locations of MyBatis mapper files.
   */
  private String[] mapperLocations;

  /**
   * Packages to search type aliases. (Package delimiters are ",; \t\n")
   */
  private String typeAliasesPackage;

  /**
   * The super class for filtering type alias. If this not specifies, the MyBatis deal as type alias all classes that
   * searched from typeAliasesPackage.
   */
  private Class<?> typeAliasesSuperType;

  /**
   * Packages to search for type handlers. (Package delimiters are ",; \t\n")
   */
  private String typeHandlersPackage;

  /**
   * Indicates whether perform presence check of the MyBatis xml config file.
   */
  private boolean checkConfigLocation = false;

  /**
   * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}.
   */
  private ExecutorType executorType;

  /**
   * The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+)
   */
  private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;

  /**
   * Externalized properties for MyBatis configuration.
   */
  private Properties configurationProperties;

  /**
   * A Configuration object for customize default settings. If {@link #configLocation} is specified, this property is
   * not used.
   */
  @NestedConfigurationProperty
  private Configuration configuration;
}

第六步:编写对应的Mapper.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.rainszj.mapper.UserMapper">

    <select id="selectAllUsers" resultType="user">
        select * from mybatis.user
    </select>
    
    <select id="findUserById" resultType="user">
        select * from mybatis.user where id = #{uid}
    </select>
    
    <update id="updateUser" parameterType="user">
        update mybatis.user 
        set name = #{name},
            pwd = #{pwd}
        where id = #{id}
    </update>


    <update id="addUser" parameterType="user">
        insert into mybatis.user values (#{id},#{name},#{pwd})
    </update>

    <delete id="deleteUser">
        delete from mybatis.user where id = #{id}
    </delete>



</mapper>

第七步:service层:

package com.rainszj.service;

import com.rainszj.mapper.UserMapper;
import com.rainszj.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public List<User> selectAllUsers() {
        return userMapper.selectAllUsers();
    }

    // 根据id查找用户
    public User findUserById(Integer id) {
        return userMapper.findUserById(id);
    }

    // 修改用户
    public int updateUser(User user) {
        return userMapper.updateUser(user);
    }

    // 添加用户
    public int addUser(User user) {
        return userMapper.addUser(user);
    }

    // 删除用户
    public int deleteUser(Integer id) {
        return userMapper.deleteUser(id);
    }


}

第八步:controller层:

package com.rainszj.controller;

import com.rainszj.pojo.User;
import com.rainszj.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {

    @Autowired
    private UserService userService;


    @GetMapping("/selectAllUsers")
    public List<User> selectAllUsers() {

        return userService.selectAllUsers();
    }


    @GetMapping("/findUserById/{id}")
    public String findUserById(@PathVariable Integer id) {
        User user = userService.findUserById(id);
        System.out.println(user);

        return "ok";
    }

    @GetMapping("/addUser")
    public String addUser() {
        userService.addUser(new User(4, "张三", "123"));
        return "ok";
    }


    @GetMapping("/updateUser")
    public String updateUser() {
        userService.updateUser(new User(4, "李四", "123"));

        return "ok";
    }

    @GetMapping("/deleteUser")
    public String deleteUser(@RequestParam("uid") Integer id) {
        userService.deleteUser(id);
        return "ok";
    }

}

测试一下就搞定 OK!

SpringBoot:整合Druid、MyBatis

原文:https://www.cnblogs.com/rainszj/p/12730716.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!