SpringBoot整合Mybatis(JDBCTemplate)

SpringBoot中Mybatis的使用

首先,我们需要在项目的pom.xml中引入mybatis的依赖和Druid连接池依赖


<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0modelVersion>
	<parent>
		<groupId>org.springframework.bootgroupId>
		<artifactId>spring-boot-starter-parentartifactId>
		<version>2.2.1.RELEASEversion>
		<relativePath/> 
	parent>
	<groupId>com.LirsgroupId>
	<artifactId>SpringartifactId>
	<version>0.0.1-SNAPSHOTversion>
	<name>Springname>
	<description>SpringBoot学习框架description>

	<properties>
		<java.version>1.8java.version>
		<mysql.version>5.0.8mysql.version>
	properties>
	
	<dependencies>
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-webartifactId>
		dependency>
		
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-testartifactId>
			<scope>testscope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintagegroupId>
					<artifactId>junit-vintage-engineartifactId>
				exclusion>
			exclusions>
		dependency>
		
		<dependency>
			<groupId>org.mybatis.spring.bootgroupId>
			<artifactId>mybatis-spring-boot-starterartifactId>
			<version>2.1.1version>
		dependency>
		
		<dependency>
			<groupId>com.alibabagroupId>
			<artifactId>druid-spring-boot-starterartifactId>
			<version>1.1.20version>
		dependency>
		
		<dependency>
			<groupId>mysqlgroupId>
			<artifactId>mysql-connector-javaartifactId>
		dependency>
		
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-jdbcartifactId>
		dependency>
	dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.bootgroupId>
				<artifactId>spring-boot-maven-pluginartifactId>
			plugin>
		plugins>
	build>

project>

Druid是一个关系型数据库连接池,是阿里巴巴的一个开源项目,
地址:https://github.com/alibaba/druid
Druid不但提供连接池的功能,还提供监控功能,可以实时查看数据库连接池和SQL查询的工作情况。

这个我之前也没用过。正好趁这次机会顺便学了。

之后就是修改配置文件application.yml

server:
  port: 8081#修改tomcat端口
  servlet:
    context-path: /Spring#修改访问路径
spring:
  datasource:
    druid:
      #数据库访问配置,我本地的mysql端口号是3307
      url: jdbc:mysql://localhost:3307/spring?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password: password
      #连接池配置
      initial-size: 5 #默认连接数
      min-idle: 5 #最小连接数
      #max-idle: 10 已经弃用
      max-wait: 30000 #连接等待超时时间
      time-between-eviction-runs-millis: 60000 #配置检测可以关闭的空间连接间隔时间
      min-eviction-idle-time-millis: 30000 #连接在池中最小生存时间
      validationQuery: select 1 #用于验证数据库连接是否有效 oracle为select 1 from dual
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      #打开PSCache,并且指定每个连接上PSCache的大小
      pool-prepared-statements: true
      max-open-prepared-statements: 20
      max-pool-prepared-statement-per-connection-size: 20
      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙
      filters: stat,wall
      # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔
      #aop-patterns: com.springboot.servie.*  暂时用不上,先注释
      # WebStatFilter配置 用于url统计 这点之后做补充学习
      web-stat-filter:
        enabled: true
        # 添加过滤规则
        url-pattern: /*
        # 忽略过滤的格式
        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
      # StatViewServlet配置 用于提供展示监控信息的html页面、JSON API
      stat-view-servlet:
        enabled: true
        # 访问路径为/druid时,跳转到StatViewServlet
        url-pattern: /druid/*
        # 是否能够重置数据
        reset-enable: false
        # 监控控制台需要账号密码才能访问
        login-username: admin
        login-password: password
          # IP白名单
          # allow: 127.0.0.1
          # IP黑名单(共同存在时,deny优先于allow)
          # deny: 192.168.1.218

          # 配置StatFilter  打开监控统计功能
      filter:
        stat:
          log-slow-sql: true

记录两个配置application.yml时犯的错:

initial-size:5	#错误的原因,冒号之后少了一个空格
initial-size: 5 #这是正确的
spring:
  datasource:
    druid:
      web-stat-filter:
        enabled: true
	  # StatViewServlet配置 用于提供展示监控信息的html页面、JSON API
      stat-view-servlet:
        enabled: true
#这里表示的配置信息:spring.datasource.druid.stat-view-servlet

上面是正确的

spring:
  datasource:
    druid:
      web-stat-filter:
        enabled: true
	  # StatViewServlet配置 用于提供展示监控信息的html页面、JSON API
        stat-view-servlet:
          enabled: true
#这里的错误在于stat-view-servlet前多了两个空格
#导致这里的配置信息变成了spring.datasource.druid.web-stat-filter.stat-view-servlet

完成配置后访问http://localhost:端口号/项目名/druid

输入账号密码之后就可以看到Durid的监控页面了。功能还是满齐全的。
SpringBoot整合Mybatis(JDBCTemplate)_第1张图片

Durid暂且放在一边

之后我们在数据库中创建一张表并添加一些数据

CREATE TABLE `tb_user` (
  `id` varchar(255) NOT NULL,
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `sex` varchar(3) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES ('1', 'admin', '123', 'f', '18');
INSERT INTO `user` VALUES ('2', 'user', '123', 'f', '18');
INSERT INTO `user` VALUES ('3', 'zhangsan', '123', 'f', '20');

创建对应的实体类

public class User {
    private String id;
    private String username;
    private String passowrd;
    private String sex;
    private int age;
    //对应的getter、setter省略

创建对应的Mapper:

这里有两种方式:

一、注解方式:

//mapper注解的作用在于让spring在初始化时为我们创建一个实体类,
//不然如果我们使用@Autowired的时候,Spring会因为找不到对应的实体类初始化而报错
@Mapper 
@Repository
public interface UserMapper {
    @Insert("insert into tb_user (id,username,password,sex,age) values(#{id},#{username},#{password},#{sex},#{ages})")
    int save(User user);
    @Update("update tb_user set username = #{username},password=#{password},#sex={sex},#{age} where id = #{id}")
    int update(User user);
    @Delete("delete from tb_user where id = #{id}")
    int deleteById(String id);
    @Select("select * from tb_user where id = #{id}")
    User selectById(String id);
    @Select("select * from tb_user")
    List<User> selectAll();
}

因为我这里没有什么实际的业务,所以就去掉了service层的业务处理,只是简单的将数据返回到前端。

Controller层就以简单的返回结果作为测试

@RequestMapping("/getAll")
public List<User> getAll(){
   return userMapper.selectAll();
}

在浏览器输入url之后就可以得到数据了
在这里插入图片描述
SpringBoot整合Mybatis(JDBCTemplate)_第2张图片
druid中也可以看到对刚才sql语句的监控情况

二、xml配置方式:

同样以刚才的mapper为例子

@Repository
@Mapper
public interface UserMapper {
    int save(User user);
    int update(User user);
    int deleteById(String id
    User selectById(String id
    List<User> selectAll();
}

在resource目录下创建一个mapeer目录,并且放入xml文件
SpringBoot整合Mybatis(JDBCTemplate)_第3张图片
并且在application.yml中还需要添加xml路径

mybatis:
  mapper-locations: classpath:mapper/*.xml

mapper.xml中的配置



<mapper namespace="com.Lirs.Spring.Mapper.UserMapper">
    
    <select id="selectAll" resultType="com.Lirs.Spring.Model.User">
        select * from tb_user
    select>
mapper>
注解方式动态SQL()

注解方式如果想使用动态sql,则需要额外创建一个SQL类

public class UserMapperProvider {
    public static String selectById(final String id){
        return new SQL(){{
            SELECT("*");
            FROM("tb_user");
            if(id != null){
                WHERE("id = #{id}");
            }
        }}.toString();
    }
}

Mapper接口

@SelectProvider(type = UserMapperProvider.class,method = "selectById")
User selectById(String id);

为什么Mapper接口需要返回的是一个User对象,而SQL类中返回的却是一个String

原因在于SQL类的父类中对toString()方法进行了重写

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sql().sql(sb);
    return sb.toString();
  }
//sql()返回一个内部类对象SqlStatement
 private final SQLStatement sql = new SQLStatement();
 private SQLStatement sql() {
   return sql;
 }
//sql(sql)返回String
public String sql(Appendable a) {
      SafeAppendable builder = new SafeAppendable(a);
      if (statementType == null) {
        return null;
      }

      String answer;

      switch (statementType) {
        case DELETE:
          answer = deleteSQL(builder);
          break;

        case INSERT:
          answer = insertSQL(builder);
          break;

        case SELECT:
          answer = selectSQL(builder);
          break;

        case UPDATE:
          answer = updateSQL(builder);
          break;

        default:
          answer = null;
      }

      return answer;
    }

其实原理就是在Spring实例化mapper时,其实是创建了一个mapper的代理对象,而代理对象内真正的方法是Provider中的方法。实际执行的也是这个方法。所以才会出现Mapper中定义的返回值是User,而SQL类中返回值是String。

注意: 如果你需要返回一个对象,那么你的mapper接口中返回值必须是对象,不能是String,如果返回值是String,那么默认只会返回查询到的记录第一列的内容

Springboot中使用jdbcTemplate

引入依赖

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

之后就可以直接使用Spring去帮我们控制jdbcTemplate

@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static final int[] TYPE = {Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.INTEGER};

    @Override
    public int save(User user) {
       String sql = "insert into tb_user (id,username,password,sex,age) values(?,?,?,?,?)";
        Object agrs[] = {user.getId(),user.getUsername(),user.getPassowrd(),user.getSex(),user.getAge()};
        return jdbcTemplate.update(sql,agrs,TYPE);

    }

    @Override
    public int update(User user) {
        String sql = "update tb_user set username = ? ,password = ? ,sex = ?, age = ? where id = '1'";
        Object args[] = {user.getUsername(),user.getPassowrd(),user.getSex(),user.getAge()};
        int argsType[] = {Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.INTEGER};
        return jdbcTemplate.update(sql,args,argsType);
    }

    @Override
    public int deleteById(String id) {
        String sql = "delete from tb_user where id = ?";
        int argsType[] = {Types.VARCHAR};
        Object args[] = {id};
        return jdbcTemplate.update(sql,args,argsType);
    }

    @Override
    public User selectById(String id) {
        String sql = "select * from tb_user where id = ?";
        Object args[] = {id};
        int argsTypes[] = {Types.VARCHAR};
        List<User> list = jdbcTemplate.query(sql,args,new UserMapper());
        if(list != null && !list.isEmpty()){
            return list.get(0);
        }
        return null;
    }


    @Override
    public List selectAll() {
        String sql = "select * from tb_user";
        List<User> users = jdbcTemplate.query(sql,new UserMapper());
        return users;
        /**
         *还可以使用这种写法。
         */
        //return jdbcTemplate.queryForList(sql);
    }
}

class UserMapper implements RowMapper<User>{

    @Override
    public User mapRow(ResultSet resultSet, int i) throws SQLException {
        User user = new User();
        user.setId(resultSet.getString("id"));
        user.setPassowrd(resultSet.getString("password"));
        user.setUsername(resultSet.getString("username"));
        user.setSex(resultSet.getString("sex"));
        user.setAge(resultSet.getInt("age"));
        return user;
    }
}

返回集合有两种方式,一种是创建一个RowMapper的子类,手动的去给集合中的对象赋值。另一个则是通过queryForList方法直接返回一个List集合,不过要注意,queryForList返回的类型是List>

返回值是长这样的:
SpringBoot整合Mybatis(JDBCTemplate)_第4张图片
每一个集合元素都是列名+值的键值对。

不过我们可以通过不指定泛型的方式直接取得一个List集合

//这里是dao层
public List selectAll() {
        String sql = "select * from tb_user";
        return jdbcTemplate.queryForList(sql);
}
//这里是controller层
@RequestMapping("/selectUseJDBC")
    public List<User> selectUseJDBC
        return userDao.selectAll();
}

这样可以成功的原因就在于java对泛型的检测只在编码阶段,这样做相当于欺骗了编译器,告诉他List里面存放的是一个Object,实际上是一个Map。然后再经由SpringMvc的@ResponseBody注解将List中的对象映射成json格式的字符串发送出去。就可以神不知鬼不觉的将一个List>当做List< User>发送出去了
在浏览器中输入地址:
在这里插入图片描述
OK!没有问题!
当然,并不推荐这种做法,因为泛型的意义就是为了在编码阶段就可以检测出集合中元素的合法性,提高程序的可读性和可维护性,但是上面这种做法无疑是会降低程序的可读性,增加程序的维护难度,所以并不推荐。不过还是可以当做一个知识点来学习。

大功告成!非常欢迎大家讨论文章的内容以及指出文章中不足或错误的地方。感谢!

你可能感兴趣的:(SpringBoot,笔记&&心得)