springboot数据库操作

本文源自上篇文章HBase_Java远程操作,上文中我自己实现了一个针对hbase的数据库连接池,当时想着自己先简单实现一个,然后再学一学现今最先进好用的数据库连接池Druid和HikariCP。加上正好在学习springboot就顺带多了解了一下springboot的数据库连接部分,关于连接池的源码阅读和自定义的连接池看下一篇文章。这里主要记录springboot和不同数据库连接池、不同数据操作方法的整合,demo见github

准备工作

采用mysql数据库(其他关系型数据库操作是一致的)

数据库名test
用户名:root
密码:root

建立一张User表

use test;
CREATE TABLE `users` (
      `username` varchar(20) NOT NULL,
      `password` varchar(20) NOT NULL,
      PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

新建基本的springboot项目

导入如下包:

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.0.0.RELEASE</version>
</parent>

<dependencies>
    <!--springboot基础包-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--springboot 数据库相关包-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

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

</dependencies>

新建UserBean.java

public class UserBean {

    private String uname;
    private String pwd;

    //....省略set、get、toString方法
}

新建application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

此时建立启动类运行就成功了,默认使用HikariDataSource作为数据源,从启动日志中可以看到:打开debug日志输出,还可以看到HikariCP连接池的启动过程,详情看下一篇文章。

数据库操作模板

目前常用的数据库操作模板有

  • JDBCTemplate
  • Mybatis
  • jpa

关于如何选择,用过就知道了,各有优劣,这里简单的讲讲怎么和springboot整合到一起,给出部分范例。每种模板都实现get,add方法。

### JDBCTemplate

新建包jdbc,操作类UserService.java

@Service
public class UserService {
    @Autowired
    JdbcTemplate jdbcTemplate;

    //通过sql语句直接执行添加
    void addUserBySql(UserBean userBean) {
        jdbcTemplate.update("INSERT INTO users(username,password)" +
                "VALUES (" + userBean.getUname() + "," + userBean.getPwd() + ")");
    }

    //通过语句预处理执行操作
    void addUserByPre(UserBean userBean) {
        String sql = "insert into users(username,password) values(?,?)";
        jdbcTemplate.update(sql, new PreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps) throws SQLException {
                ps.setString(1, userBean.getUname());
                ps.setString(2, userBean.getPwd());
            }
        });
    }

    //通过查询函数执行操作
    List<UserBean> getUsersByQuery() {
        List<Map<String, Object>> list = jdbcTemplate.queryForList("SELECT * FROM USERS");
        List<UserBean> res = new ArrayList<>();
        for (Map<String, Object> map : list) {
            UserBean userBean = new UserBean();
            userBean.setUname((String) map.get("username"));
            userBean.setPwd((String) map.get("password"));
            res.add(userBean);
        }
        return res;
    }

    //通过语句预处理执行操作
    List<UserBean> getUsersByExcute(String name) {
        String sql = "select * from users where username=?";
        List<UserBean> list = jdbcTemplate.execute(sql, new PreparedStatementCallback<List<UserBean>>() {
            @Nullable
            @Override
            public List<UserBean> doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
                ps.setString(1, name);
                ResultSet resultSet = ps.executeQuery();
                List<UserBean> list = new ArrayList<>();
                while (resultSet.next()) {
                    UserBean bean = new UserBean();
                    bean.setUname(resultSet.getString("username"));
                    bean.setPwd(resultSet.getString("password"));
                    list.add(bean);
                }
                return list;
            }
        });
        return list;
    }

}

以上可以看出,使用jdbcTemplate非常自由,只需要注入JdbcTemplate的bean即可,然后可以自定义sql,比较麻烦的是要自行封装数据。

可以看到jdbcTemplate的方法很简单,只有execute()、query()、update()几类,然后参数又分为sql和参数预处理。使用起来很方便了。我们接下来看看结果。新建一个IndexController类,按方法名绑定访问参数。

//只需要返回结果即可,不用做前端处理
@RestController
public class IndexController {
    //JdbcTempale 模板使用

    private final UserService userService;

    @Autowired
    public IndexController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/jdbc/addUserBySql")
    public String addUserBySql() {
        for (int i = 0; i < 5; i++) {
            UserBean userBean = new UserBean("changfubai-jdbc-" + i,
                    "password-jdbc-" + i);
            userService.addUserBySql(userBean);
        }
        List<UserBean> users = userService.getUsersByQuery();
        StringBuffer bf = new StringBuffer("getUsersByQuery:-----");
        for (UserBean user : users) {
            bf.append(user.toString());
        }
        return bf.toString();
    }

    @GetMapping("/jdbc/addUserByPre")
    public String addUserByPre() {
        for (int i = 10; i < 15; i++) {
            UserBean userBean = new UserBean("changfubai-jdbc-" + i,
                    "password-jdbc-" + i);
            userService.addUserByPre(userBean);
        }
        List<UserBean> users = userService.getUsersByExcute();
        StringBuffer bf = new StringBuffer("getUsersByExcute:-----");
        for (UserBean user : users) {
            bf.append(user.toString());
        }
        return bf.toString();
    }
}

浏览器访问:http://localhost:8080/jdbc/addUserBySql 以及 http://localhost:8080/jdbc/addUserByPre 即可得到已经插入的结果。

mybatis

上一种方式虽然有写sql的快感,但是java代码也是一堆一堆的,所以我们使用mybatis做整合,这里只使用注解的方式,会有种很爽的感觉。

配置maven依赖,直接在中央仓库找一个来用就行了

<!--mybatis依赖-->
<dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.0</version>
</dependency>

新建mapper包,并将该包加入注解扫描,在springboot启动类上加入注解即可。

@MapperScan("com.changfubai.springboot.database.mapper")

在mapper包下新建UserMapper.java

//IDEA不能自动识别bean,会有错误警告,不影响运行结果
// 加上该注解即可消除错误提示
@Repository
public interface UserMapper {
    @Insert("insert into users(username,password) values(#{uname},#{pwd})")
    public void add(UserBean userBean);

    //这里的属性名和数据库表中的不相同,所以需要手动映射Results
    @Select("select * from users")
    @Results({
            @Result(property = "uname", column = "username"),
            @Result(property = "pwd", column = "password")
    })
    public List<UserBean> getUsers();

    //这里的属性名和数据库表中的不相同,所以需要手动映射Results
    @Select("select * from users where username = #{username}")
    @Results({
            @Result(property = "uname", column = "username"),
            @Result(property = "pwd", column = "password")
    })
    UserBean getUserByName(@Param("username") String name);
}

然后在IndexController中继续添加

//mybatis 模板使用
@Autowired
UserMapper userMapper;

@GetMapping("/mybatis/addUser")
public String addUser() {
    for (int i = 0; i < 5; i++) {
        UserBean bean = new UserBean("changfubai-mybatis-" + i, "pwd-mybatis-" + i);
        userMapper.add(bean);
    }
    List<UserBean> users = userMapper.getUsers();
    StringBuffer bf = new StringBuffer("mybatis-addUser:");
    for (UserBean user : users) {
        bf.append(user.toString());
    }
    return bf.toString();
}
@GetMapping("/mybatis/getUserByName")
public String getUserByName() {
    UserBean userByName = userMapper.getUserByName("changfubai-mybatis-1");
    return userByName.toString();
}

浏览器访问 http://localhost:8080/mybatis/addUserhttp://localhost:8080/mybatis/getUser 即可得到正确的结果。

这里不难看出mybatis的优越性了,既可以自己敲sql,又可以帮忙完成数据的自动注入,代码清晰了很多,用起来也超级舒服。

但这里也有个问题,既然mybatis只需要实现mapper接口就可以了,那能不能实现一个公用的接口mapper,这样大部分的sql都不用重写,直接继承就可以了。关于这一点,我在SSM框架的搭建过程中就实现了mybatis的共用模板设计,这个网上好像没有特别完整的,大家可以参考我的github上的mybatis-spring。 这里还同时集成了实体类的自动生成,通过扫描数据库表自动生成,以及分页模板。有空可以考虑重写一个springboot版本的mybatis详解。

jpa

jpa其实只是一种通用模式,hibernate就是jpa的一种具体实现,所以大家可以很清楚的感受到其优点,就是对象自动映射,不需要写sql,哇,懒汉专用。 jpa和mybatis的比较,看这里

jpa和springboot的整合,导入依赖

<!--jpa依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

jpa可以根据实体类自动生成或更新表,我们可以在application.yml中配置一下

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
  jpa:
#    展示sql
    show-sql: true
#    根据实体类自动更新表
    hibernate:
      ddl-auto: update

然后重新创建一个新的实体类UserEntity.java

@Entity
public class UserEntity {

    public UserEntity() {
    }

    public UserEntity(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Id
    @GeneratedValue
    private Long id;


    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private Integer age;

    //省略set、get、toString方法

}

然后创建一个UserRepository.java类继承接口JpaRepository即可。

//JpaRepository中定义了大量常用的操作方法,我们可以在自定义的接口中定义新的方法,也可以在实现接口后重写
public interface UserRepository extends JpaRepository<UserEntity, Long> {

}

然后补充IndexController类

//jpa 模板使用
@Autowired
UserRepository userRepository;

@GetMapping("/jpa/addUserByJpa")
public String addUserByJpa() {
    List<UserEntity> list = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        list.add(new UserEntity("changfubai-jpa-" + i, 20 + i));
    }
    userRepository.saveAll(list);
    List<UserEntity> all = userRepository.findAll();
    StringBuffer bf = new StringBuffer("JPA:");
    for (UserEntity entity : all) {
        bf.append(entity.toString());
    }
    return bf.toString();
}

浏览器访问 http://localhost:8080/jpa/addUserByJpa 即可得到结果。

我们也可以自己写sql,不过支持的语法是HQL的形式,我们在UserRepository接口中新增方法:

//可以忽略IDEA的提示
@Query("from UserEntity u where u.name=:name")
    UserEntity findUser(@Param("name") String name);

然后补充IndexController类

@GetMapping("/jpa/findUser")
public String findUser() {
    UserEntity user = userRepository.findUser("changfubai-jpa-1");
    return user.toString();
}

浏览器访问 http://localhost:8080/jpa/findUser 即可得到结果。

到这里就可以看到优劣了,jpa完全傻瓜式的,不需要依赖于sql就能完成数据持久化过程,当然还有更多高级的用法,需要大家自行了解了。

使用durid作为数据库连接池

druid是阿里的开源作品,擅长于监控数据。导入依赖:

<!--druid 依赖-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.9</version>
</dependency>

然后运行就会自动切换成druid了,关于监控的配置可以看官网的,启动项目后,可以在输出控制台看到

在浏览器打开 http://localhost:8080/druid/index.html 即可进入监控页面。

总结

本文介绍了三种数据库模板,使用起来各有优劣,具体选择哪个完全看业务需求和规范,爱好等。但基本使用都是很简单的呢。做为小白,记录自己的学习过程,有不妥当的地方,欢迎指出,请联系我 [email protected]

Fork me on GitHub