Springboot-持久化支持

1、JDBC(Java数据库连接)

JDBC(Java Database Connectivity)是一种Java API,用于连接数据库并执行查询。它是来自Sun微系统的规范,为Java应用程序提供标准抽象(API或协议)以与各种数据库进行通信。它为语言提供了Java数据库的连接标准,用于编写访问数据库所需的程序。JDBC连同数据库驱动程序可以访问数据库和电子表格,可以借助JDBC API访问存储在关系数据库(RDB)中的企业数据。

1.1 JDBC 的目的

使用 JAVA EE 技术创建的企业应用程序需要与数据库交互以存储特定于应用程序的信息。因此,与数据库交互需要高效的数据库连接,这可以通过使用ODBC(开放式数据库连接)驱动程序来实现。此驱动程序与 JDBC 一起使用,以与各种数据库(如 Oracle、MS Access、Mysql 和 SQL 服务器数据库)进行交互或通信。

1.2 JDBC 的组件

JDBC 通常有四个主要组件,通过它们可以与数据库进行交互。它们如下所述:

  1. JDBC API:提供各种方法和接口,方便与数据库进行通信。它提供如下两个包,其中包含java SE和Java EE平台,以展示WORA(write once run anywhere)能力。
java.sql.*;

它还提供了将数据库连接到客户端应用程序的标准。
2. JDBC驱动程序管理器(JDBC Driver):它在应用程序中加载特定于数据库的驱动程序以建立与数据库的连接。它用于对数据库进行特定于数据库的调用以处理用户请求。
3. JDBC Test suite:用于测试JDBC Drivers执行的操作(如插入、删除、更新)。
4. JDBC-ODBC 桥接驱动程序:它将数据库驱动程序连接到数据库。此桥将 JDBC 方法调用转换为 ODBC 函数调用。它利用包含本地库的sun.jdbc.odbc包来访问 ODBC 特性。

1.3 JDBC常用接口

  • JAVA API:提供对JDBC的管理链接;
  • JAVA Driver API:支持JDBC管理到驱动器连接。
  • DriverManager:这个类管理数据库驱动程序的列表,查看加载的驱动是否符合JAVA Driver API的规范。
  • Connection:与数据库中的所有的通信是通过唯一的连接对象。
  • Statement:把创建的SQL对象,转而存储到数据库当中。
  • ResultSet:它是一个迭代器,用于检索查询数据。

1.4 JDBC体系结构

在这里插入图片描述

1.5 JDBC的工作

需要与数据库通信的Java应用程序必须使用JDBC API进行编程。必须在Java应用程序中添加支持Oracle和SQL Server等数据源的JDBC驱动程序才能支持JDBC。此JDBC驱动程序智能地与相应地数据源进行通信。
连接前需要先添加对应版本的MySQL驱动,我这里用的是8.0.21版本。
https://mvnrepository.com/可以去Maven仓库下载对应的驱动包。

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

1.5.1 JDBC连接测试

public class JDBCdemo {
    public static void main(String[] args) {
        Connection con;
        //jdbc驱动Driver
        //我这里的MySQL版本为8.0.21,如果是5.0版本的driver为"com.mysql.jdbc.Driver"
        String driver="com.mysql.cj.jdbc.Driver";
        //这里我的数据库是goods,根据自己的数据库修改名称
        String url="jdbc:mysql://localhost:3306/goods?&useSSL=false&serverTimezone=UTC";
        String user="root";
        String password="123456";
        try {
            //注册JDBC驱动程序
            Class.forName(driver);
            //建立连接
            con = DriverManager.getConnection(url, user, password);
            if (!con.isClosed()) {
                System.out.println("数据库连接成功");
            }
            con.close();
        } catch (ClassNotFoundException e) {
            System.out.println("数据库驱动没有安装");

        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("数据库连接失败");
        }
    }
}

1.5.2 创建一个简单的JDBC应用程序

/**
 * JDBC API:Statement
 **/
public class JDBCdemo2 {
       @Test
       /*
       * 执行DML语句
       * @throw Exception
       * */
    public void testDML() throws Exception{
       //1.注册驱动
       Class.forName("com.mysql.cj.jdbc.Driver");
       //2.获取连接
       String url = "jdbc:mysql://localhost:3306/goods?&useSSL=false&serverTimezone=UTC";
       String username = "root";
       String password = "123456";
       Connection conn = DriverManager.getConnection(url,username,password);

       //3.定义SQL
       String sql1 = "update account set money = 3000 where id = 1";
       String sql2 = "INSERT INTO account(id ,name ,money) VALUES (3,'王五',5000);";
       //4.获取执行SQL的对象Statement
       Statement stmt = conn.createStatement();

       //5.执行SQL
       int count1 = stmt.executeUpdate(sql1);//受影响的行数
       int count2 = stmt.executeUpdate(sql2);

       //6.处理结果
       //System.out.println(count);
       if(count1 > 0){
           System.out.println("修改成功!");
       }else{
           System.out.println("修改失败!");
       }

        if(count2 > 0){
            System.out.println("修改成功!");
        }else{
            System.out.println("修改失败!");
        }

        //7.释放资源
       stmt.close();
       conn.close();
    }

    /*
    * 执行DDL语句
    * */

    public void testDDL() throws Exception{
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.获取连接
        String url = "jdbc:mysql://localhost:3306/goods?&useSSL=false&serverTimezone=UTC";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url,username,password);

        //3.定义SQL
        String sql1 = "create table db2";
        //String sql2 = "INSERT INTO account(id ,name ,money) VALUES (3,'王五',5000);";
        //4.获取执行SQL的对象Statement
        Statement stmt = conn.createStatement();

        //5.执行SQL
        int count1 = stmt.executeUpdate(sql1);//受影响的行数
        //int count2 = stmt.executeUpdate(sql2);

        //6.处理结果
        //System.out.println(count);
        if(count1 > 0){
            System.out.println("修改成功!");
        }else{
            System.out.println("修改失败!");
        }

        /*
        if(count2 > 0){

            System.out.println("修改成功!");
        }else{
            System.out.println("修改失败!");
        }
        */

        //7.释放资源
        stmt.close();
        conn.close();
    }
}

1.5.3 结果集接口ResultSet

/**
 * JDBC API:Statement
 **/
public class JDBCdemo3_ResultSet {
       @Test
    /*
     * 查询account账户数据,封装为Account对象中,并且存储到ArrayList集合中
     * 1.定义实体类Account
     * 2.查询数据,封装到Account对象中
     * 3.将Account对象存入ArrayList对象中
     *
     * @throw Exception
     * */
    public void testResultSet2() throws Exception{
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.获取连接
        String url = "jdbc:mysql://localhost:3306/goods?&useSSL=false&serverTimezone=UTC";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url,username,password);
        //3.定义SQL
        String sql = "select * from account";
        //4.获取statement对象
        Statement stmt = conn.createStatement();
        //5.执行sql
        ResultSet rs = stmt.executeQuery(sql);
        //创建集合
        List<Account>list = new ArrayList<>();


        //6.1光标向下移动,并且判断当前行是否有数据
        while (rs.next()){
            Account account = new Account(); //创建account对象
        //6.2获取数据 getXxx()
            int id=rs.getInt("id");
            String name = rs.getString("name");
            double money = rs.getDouble("money");
            //赋值
             account.setId(id);
             account.setName(name);
             account.setMoney(money);
             //存入集合
            list.add(account);
        }
        System.out.println(list);

        //7.释放资源
        rs.close();;
        stmt.close();
        conn.close();

        }
}

1.5.4 JDBC-PrepareStatement

/**
 * JDBC API: PrepareStatement
 **/
public class JDBCdemo5_PreparedStatement {
    @Test

    public void testLogin() throws Exception {
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.获取连接
        String url = "jdbc:mysql://localhost:3306/goods?&useSSL=false&serverTimezone=UTC";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, username, password);

        //接收用户输入的用户名和密码
        String name = "zhangsan";
        String passward = "123";

        //定义 SQL
        String sql = "select * from tb_user where username = ? and passward = ?";

        //获取stmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        //设置set的值
        pstmt.setString(1,name);
        pstmt.setString(2,passward);

        //执行sql
        ResultSet rs = pstmt.executeQuery();

        //判断登录是否成功
        if(rs.next()){
            System.out.println("登录成功!");
        }else {
            System.out.println("登录失败!");
        }

        //7.释放资源
        rs.close();
        pstmt.close();
        conn.close();
        }
}

2、Spring Data JPA

JPA(Java Persistence API)是更大的Spring Data系列的一部分,可以轻松实现基于JPA的存储库。该模块处理基于JPA的数据访问层的增强支持。它使构建使用数据访问技术的Spring驱动的应用程序变得更加容易。
特点:

  • 对基于Spring和JPA构造存储库的完事支持;
  • 支持Querydsl谓词,从而支持类型安全的JPA查询;
  • 域类的透明审计;
  • 分页支持,动态查询执行,能够集成自定义数据访问代码;
  • 在引导时验证@Query注释查询;
  • 支持基于XML的实体映射;
  • 通过引入@EnableJpaRepositories实现基于JavaConfig的存储库配置。

3、Druid数据源置换

Druid是阿里提供的数据源,有连接池,自带监控页面,效率高。

3.1 Druid数据连接池创建

首先需要在项目中引入Druid的依赖包。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>

创建druid. properties

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/goods?&useSSL=false&serverTimezone=UTC&useServerPrepStmts=true
username=root
password=123456
#初始化连接数量
initialSize=5
#最大连接数
maxActive=10
#最大等待时间
maxWait=3000

Druid数据库连接池演示

public class DruidDemo {
    @Test
    /*
		Druid数据库连接池演示
	*/
    public void main() throws Exception {
        //1.导入jar包

        //2.定义配置文件

        //3.加载配置文件
        Properties prop = new Properties();

        prop.load(new FileInputStream("C:/Users/zhzg/Desktop/test/javaweb_study/jdbc-demo/src/com/sise/druid/druid.properties"));

        //4.获取连接持对象
        DataSource dataSource= DruidDataSourceFactory.createDataSource(prop);

        //5.获取数据库连接
        Connection connection = dataSource.getConnection();

        System.out.println(connection);
        
        System.out.println(System.getProperty("user.dir"));
    }
}

3.2 Druid数据监控

配置application.yml

spring:
  datasource:
    username: root
    password: zhzg020518
    url: jdbc:mysql://localhost:3306/mybatis?&useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #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

创建DruidConfig后台监控

@Configuration
public class DruidConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }

    //后台监控  :web.xml,ServletRegistrationBean
    //因为springboot内置了servlet容器,所有没有web.xml,替代方法ServletRegistrationBean
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean<StatViewServlet>bean=new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");

        //后台登录账号密码
        HashMap<String,String> initParameters = new HashMap<>();

        //添加配置,loginUsername、loginPassword固定参数不能改变
        initParameters.put("loginUsername","admin");
        initParameters.put("loginPassword","123456");

        //允许访问
        initParameters.put("allow","");//空值所有人都可以访问。localhost本机才能访问

        //禁止访问
        //initParameters.put("","");//用户名,ip禁止该用户进行访问

        bean.setInitParameters(initParameters);//初始化参数
        return bean;
    }

    //filter配置过滤器
    @Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();

        bean.setFilter(new WebStatFilter());

        //过滤请求
        Map<String,String>initParameters = new HashMap<>();

        initParameters.put("exclusions","*.js,*.css,/druid/*");//不进行拦截
        bean.setInitParameters(initParameters);

        return bean;
    }
}

4、ORM框架

ORM(Object Relational Mapping)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。ORM框架是连接数据库的桥梁,只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。

4.1 整合Mybatis

Mybatis是一种常用的ORM框架,也是SSM(Spring+SpringMVC+Mybatis)三大框架之一。

4.1.1 配置与使用

文件结构
在这里插入图片描述

导入Mybatis依赖:

<!--mybatis-spring-boot-starter-->
<dependency>
		<groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

yml配置文件:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?&useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

mybatis:
  mapperLocations: classpath:classpath:mybatis/mapper/*.xml # mapper xml 文件地址	
  type-aliases-package: com.mybatis.pojo # 根据自己的pojo/entity包的位置进行修改

pojo数据实例化:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private int id;
    private String username;
    private String password;
    private String gender;
    private String addr;
}

UserMapper.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.mybatis.mapper.UserMapper">

  <select id="queryUserList" resultType="User">
    select * from tb_user
  </select>

  <select id="queryUserById" resultType="User">
    select * from tb_user where id = #{id}
  </select>

  <insert id="addUser" parameterType="User">
    insert into tb_user (id,username,password,gender,addr)  values (#{id},#{username},#{password},#{gender},#{addr})
  </insert>

  <update id="updateUser" parameterType="User">
    update tb_user set username=#{username},password=#{password},gender=#{gender},addr=#{addr} where id=#{id}
  </update>

  <delete id="deleteUser" parameterType="int">
    delete from tb_user where id = #{id}
  </delete>
</mapper>

定义UserMapper接口:

@Mapper
@Repository
public interface UserMapper {

    List<User> queryUserList();

    User queryUserById(int id);

    int addUser(User user);

    int updateUser(User user);

    int deleteUser(int id);
}

UserController实现页面请求控制:

@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @GetMapping("/queryUserList")
    public List<User> queryUserList(){
        List<User> userList=userMapper.queryUserList();
        for(User user : userList){
            System.out.println(user);
        }
        return userList;
    }

    //添加一个用户
    @GetMapping("/addUser")
    public String addUser(){
        userMapper.addUser(new User(5,"小明","123456","男","广州"));
        return "ok";
    }
    //修改一个用户
    @GetMapping("/updateUser")
    public String updateUser(){
        userMapper.updateUser(new User(5,"xiaoming","123456","男","广州"));
        return "ok";
    }
    //根据id删除一个用户
    @GetMapping("/deleteUser")
    public String deleteUser(){
        userMapper.deleteUser(5);
        return "ok";
    }
}

4.1.2 Mybatis优缺点

一、MyBatis框架的优点:
  1. 与JDBC相比,减轻了50%以上的代码量。 
  2. MyBatis是最简单的持久化框架,小巧并且简单易学。 
  3. MyBatis灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,可重用。 
  4. 提供XML标签,支持编写动态SQL语句(XML中使用if, else)。  
  5. 提供映射标签,支持对象与数据库的ORM字段关系映射(在XML中配置映射关系,也可以使用注解)。
二、MyBatis框架的缺点:  
  1. SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求。 
  2. SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
三、MyBatis框架适用场合:
  MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。  
  对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。

4.2 Spring Data JPA

4.2.1 配置与使用

导入JPA依赖:

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

yml配置文件:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?&useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  jpa:
    hibernate:
      ddl-auto: update //自动更新
    show-sql: true  //日志中显示sql语句
#ddl-auto参数:
#create:每次运行程序时,都会重新创建表,故而数据会丢失
#create-drop:每次运行程序时会先创建表结构,然后待程序结束时清空表
#upadte:每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新(推荐使用)
#validate:运行程序会校验数据与数据库的字段类型是否相同,字段不同会报错
#one: 禁用DDL处理

入口类添加@EnableJpaRepositories注解:

@SpringBootApplication
@EnableJpaRepositories
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }

pojo数据实例化:

@Entity
@Table(name = "user")
@Data
public class User {

    @Id
    @GenericGenerator(name = "idGenerator", strategy = "uid")
    @GeneratedValue(generator = "idGenerator")
    private String id;

    @Column(name = "username", unique = true, nullable = false, length = 64)
    private String username;

    @Column(name = "password", nullable = false, length = 64)
    private String password;
}

定义DAO数据接口:

public interface UserRepository extends JpaRepository<User, String> {
}

创建Server服务,实现对数据库增删改查操作:

public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User saveUser(User user) {
        return userRepository.save(user);
    }

    public void deleteUser(String userId) {
        userRepository.deleteById(userId);
    }

    public User updateUser(String userId, User user) {
        user.setId(userId);
        return userRepository.save(user);
    }

    public User getUserInfo(String userId) {
        return userRepository.findById(userId);
    }

    public Page<User> pageQuery(Integer pageNum, Integer pageSize) {
        return userRepository.findAll(PageRequest.of(pageNum - 1, pageSize));
    }

}

UserController对页面请求作出响应:

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping()
    public User saveUser(@RequestBody User user) {
        return userService.save(user);
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable("id") String userId) {
        userService.deleteById(userId);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable("id") String userId, @RequestBody User user) {
        user.setId(userId);
        return userService.save(user);
    }

    @GetMapping("/{id}")
    public User getUserInfo(@PathVariable("id") String userId) {
        return userService.getUserInfo(userId);
    }

    @GetMapping("/list")
    public Page<User> pageQuery(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                                @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
        return userService.pageQuery(pageNum, pageSize);
    }

}

4.2.2 JPA注解

@Entity声明类为实体或表
@Table声明表名
@Basic指定非约束明确的各个字段
@Embedded指定类或它的值是一个可嵌入的类的实例的实体的属性
@Id指定的类的属性,用于识别(一个表中的主键)
@GeneratedValue指定如何标识属性可以被初始化,例如自动、手动、或从序列表中获得的值
@Transient指定的属性,它是不持久的,即:该值永远不会存储在数据库中
@Column指定持久属性栏属性
@SequenceGenerator指定在@GeneratedValue注解中指定的属性的值。它创建了一个序列
@TableGenerator指定在@GeneratedValue批注指定属性的值发生器。它创造了的值生成的表
@AccessType这种类型的注释用于设置访问类型。如果设置@AccessType(FIELD),则可以直接访问变量并且不需要getter和setter,但必须为public 。 如果设置@AccessType(PROPERTY),通过getter和setter方法访问Entity的变量
@JoinColumn指定一个实体组织或实体的集合。这是用在多对一和一对多关联
@UniqueConstraint指定的字段和用于主要或辅助表的唯一约束
@ColumnResult参考使用select子句的SQL查询中的列名
@ManyToMany定义了连接表之间的多对多一对多的关系
@ManyToOne定义了连接表之间的多对一的关系
@OneToMany定义了连接表之间存在一个一对多的关系
@OneToOne定义了连接表之间有一个一对一的关系
@NamedQueries指定命名查询的列表
@NamedQuery指定使用静态名称的查询

4.3 Hibernate、JPA、Spring Data JPA 三者之间的区别与联系

1、Hibernate 是持久化实现技术,是一种 ORM 框架;
2、JPA 是持久化的标准,一个是具体实现,一个是接口协议;
3、Spring Data JPA 是在 Hibernate 的基础上更上层的封装实现。

5、总结

1、JDBC数据连接
2、Spring Data JPA
3、Druid数据连接池
4、Mybatis应用简单开发
5、Spring Data JPA应用简单开发

MYBLOG:http://180.76.231.251/archives/springboot-%E6%8C%81%E4%B9%85%E5%8C%96%E6%94%AF%E6%8C%81

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值