spring boot在项目中同时使用 jpa 与MyBatis操作数据库

该教程介绍了如何在SpringBoot项目中同时配置和使用JPA与MyBatis。主要内容包括配置数据库连接、编写实体类、DAO接口、Controller以及Thymeleaf模板展示数据。示例代码展示了JPA的原生SQL查询和对象查询,以及MyBatis的数据访问。此外,还通过Java Stream进行了二次查询操作。提供了完整的项目结构和配置信息。

spring boot mvc 基本配置和mybatis配置与操作请参考前面的博客。

小型项目可能jpa使用更便捷,在大型项目中更多会考虑安全和性能要求,在这方面半自动的mybatis则更具有优势。

本教程提供一个简单的spring boot数据库操作案例,包括了jpa和mybatis的整合,但本文主要给了jpa的数据库操作,而在示例代码中提供了jpa和mybatis的共同配置和使用,更详细的内容请参考官方文档注意,由于spring boot版本之间差别,应该根据项目配置查看相应的帮助文档)

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference

项目结构如下:

 

1、在pom.xml添加依赖

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

  application.properties文件内容(有jpa配置和mybatis配置) 

spring.
   thymeleaf:
    prefix: "classpath:/templates/"
    suffix: ".html"
    
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 
# Hikari will use the above plus the following to setup connection pooling
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=25
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=3000
spring.datasource.hikari.pool-name=DatebookHikariCP
spring.datasource.hikari.max-lifetime=200000
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.connection-test-query=SELECT 1

mybatis.typeAliasesPackage=com.example.demo.entity
mybatis.mapper-locations=classpath:/mapper/*Mapper.xml

#jpa configuration
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

 

2、编写实体类(注意包的位置)

 

package com.example.demo.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="product")
public class Product {
	@Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String productName;
    
	@Column(nullable = true)
    private String location;

//    @Column(nullable = false, unique = true)
	@Column(nullable = false)
    private String email;

    public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	public String getLocation() {
		return location;
	}
	public void setLocation(String location) {
		this.location = location;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
    
    public Product(String name,String location,String email){
    	this.productName=name;
    	this.location=location;
    	this.email=email;    	
    	
    }
    public Product(){}
}

注解一目了然,不多说

3、编写Dao类

package com.example.demo.dao;

import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import com.example.demo.entity.Product;

public interface ProductRepository extends CrudRepository<Product,Long>{
	List <Product> findByProductName(String name);
	List <Product> findByProductNameContaining(String name);
	//原生态ssql查询
	@Query(value="select * from product", nativeQuery=true)
	List <Product> MyQueryAll();

	//以下是jpa提供的对象方式查询
	@Query("select p from Product p")
	List <Product> MyQueryAll2();
	
	@Query("select p from Product p where p.productName like %:name%")
	List <Product> MyQueryAll3(@Param("name") String name);	
	
	@Query("select p.productName from Product p where p.productName like %:name%")
	List <String> MyQueryAll4(@Param("name") String name);
}

上面代码中提供了原生态的sql查询@Query(value="select * from product", nativeQuery=true) 和若干jpa对象查询,注意他们之间的区别。代码比较简单不展开阐述。注意:@Param一定要引用org.springframework.data.repository.query.Param的,不用引用了mybatis的org.apache.ibatis.annotations.Param,否则要错误

4、编写Controller类

package com.example.demo.controllers;

import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.demo.dao.ProductRepository;
import com.example.demo.dao.UserDao;
import com.example.demo.dao.UserMapper;
import com.example.demo.entity.Product;
import com.example.demo.entity.User;
import com.example.demo.services.SearchService;

@Controller
public class HelloController {
	@Autowired
	SearchService sv;
	@Autowired
	UserMapper us;
	@Autowired
	UserDao userDao;
	@Autowired
	ProductRepository jpa;
	
    //以下是mybatis访问的数据库
	@RequestMapping("/index")
	public String hello(Model m, HttpSession session) {
		m.addAttribute("person", "张三");
		System.out.println(sv.getinformation("12345"));
		List<User> userlist = us.queryAllUser();
		m.addAttribute("userlist", userlist);
		User sUser = new User();
		sUser.setName("Admin");
		sUser.setAge(30);
		session.setAttribute("sUser", sUser);

		User us = userDao.findById(6);
		System.out.println("通过注解方式获得的User信息如下:");
		System.out.println(us.getName());
		return "index";
	}
    //以下是用jpa访问的数据库
	@RequestMapping("/testjpa")
	// @ResponseBody
	public String hello2(Model m) {
		Product pd = new Product();
		pd.setLocation("厦门");
		pd.setEmail("test@163.com");
		pd.setProductName("显卡");
		jpa.save(pd);

		List<Product> pdlist = jpa.findByProductNameContaining("鼠标");
		m.addAttribute("pdlist", pdlist);

		List<Product> all = jpa.MyQueryAll();
		for (Product p : all)
			System.out.println("产品名称:" + p.getProductName() + "  产地是:" + p.getLocation() + "\n");

		all = jpa.MyQueryAll2();
		System.out.println("second query");
		for (Product p : all)
			System.out.println("产品名称:" + p.getProductName() + "  产地是:" + p.getLocation() + "\n");

		all = jpa.MyQueryAll3("鼠标");
		System.out.println("third query");
		for (Product p : all)
			System.out.println("产品名称:" + p.getProductName() + "  产地是:" + p.getLocation() + "\n");

		List<String> strs = jpa.MyQueryAll4("鼠标");
		System.out.println("fourth query");
		for (String p : strs)
			System.out.println("产品名称:" + p + "\n");

		return "result";

	}

}

5、增加一个Controller对重数据库中的结果,用java的stream进行二次查询操作。

package com.example.demo.controllers;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.dao.ProductRepository;
import com.example.demo.entity.Product;
@RestController
public class SteamController {
	@Autowired
	ProductRepository jpa;

	@RequestMapping("/stream")
	public String handler() {
		List<Product> plist = jpa.MyQueryAll();
		// 筛选
		List<Product> list2 = plist.stream().filter(a -> a.getLocation().equals("厦门")).collect(Collectors.toList());
		String str = "";
		for (Product p : list2) {
			str += "产品名称:" + p.getProductName() + "  产地是:" + p.getLocation() + "<br/>";
			System.out.println("产品名称:" + p.getProductName() + "  产地是:" + p.getLocation() + "\n");
		}

		// 排序
		list2 = plist.stream().sorted(Comparator.comparing(Product::getProductName).reversed())
				.collect(Collectors.toList());
		str += "<br/><br/>排序后的输出:<br/><br/>";
		System.out.println("排序后的输出:");
		for (Product p : list2) {
			str += "产品名称:" + p.getProductName() + "  产地是:" + p.getLocation() + "<br/>";
			System.out.println("产品名称:" + p.getProductName() + "  产地是:" + p.getLocation() + "\n");
		}
		// 求和
		Long sum = plist.stream().map(Product::getId).reduce(0L, (a, b) -> a + b);
		System.out.println(sum);

		sum = plist.stream().map(Product::getId).reduce(0L, Long::sum);
		System.out.println(sum);

		return str;
	}
}

 6、页面(thymeleaf模板)

result.html页面 ,用以显示jpa查询结果

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div>
<table border="1"  cellspacing="0">
    <tr>
        <th>产品名称</th>
        <th>产品源地</th>   
    </tr>
    <tr  th:each="pd : ${pdlist}" >
        <td th:text="${pd.productName}"></td>
        <td th:text="${pd.location}"></td>
 
    </tr>
</table>
<br/>
  
</div>
</body>
</html>

 index.html页面 ,用以显示mybatis查询结果

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
 
<table border="1"  cellspacing="0">
    <tr>
        <th>姓名</th>
        <th>年龄</th>   
    </tr>
    <tr  th:each="user : ${userlist}" >
        <td th:text="${user.name}"></td>
        <td th:text="${user.age}"></td>
 
    </tr>
</table>
<br/>
 
<span>th:text不能够写出 th: text 中间不能用空格</span>
<div th:object="${session.sUser}">
<p>姓名: <span th:text="*{name}" >Sebastian</span>. </p> 
<p>年龄: <span th:text="*{age}" >Pepper</span>. </p>
</div>
<!-- <p>姓名: <span th:text="${session.sUser.name}" ></span>. </p> -->
</div>
</body>
</html>

7、浏览器输出结果 

(1)jpa输出结果

 

(2)mybatis输出结果 

(3)jpa在控制台输出结果 

 (4)在页面stream查询操作输出

示例代码下载:https://pan.baidu.com/s/1xw38WFVRAvzd5kCnR9jBAA 提取码: pjhw 复制这段内容后打开百度网盘手机App,操作更方便哦

<think>我们将在Spring Boot项目中集成MyBatis替代JPA,主要步骤包括:添加依赖、配置数据源、创建实体类、Mapper接口XML映射文件、Service层、Controller层,以及配置MyBatis。 注意:由于之前使用JPA,现在要替换为MyBatis,需要移除JPA相关依赖,并添加MyBatis依赖。 步骤详细说明如下: 1. 添加MyBatisMySQL驱动依赖 在pom.xml中,移除Spring Data JPA依赖(如果存在),添加MyBatis Spring Boot StarterMySQL驱动依赖。 2. 配置数据源MyBatis 在application.properties(或application.yml)中配置数据源MyBatis相关属性,如Mapper XML文件的位置、实体类包等。 3. 创建实体类 创建数据库表对应的实体类(POJO),例如Teacher类。 4. 创建Mapper接口XML映射文件 创建Mapper接口,定义数据库操作方法,并在XML文件中编写SQL语句。 5. 创建Service层 创建Service接口及其实现,调用Mapper接口中的方法。 6. 创建Controller层 创建RESTful API,调用Service层方法返回数据。 7. 在启动类上添加@MapperScan注解 指定Mapper接口所在的包,让Spring Boot能够扫描到Mapper接口。 下面我们详细展开每一步: ### 1. 添加依赖 在pom.xml中添加以下依赖: ```xml <!-- MyBatis Spring Boot Starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> <!-- 请使用最新版本 --> </dependency> <!-- MySQL 驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> ``` 同时,移除Spring Data JPA的依赖(如果之前有的话)。 ### 2. 配置数据源MyBatis 在`application.properties`中配置: ```properties # 数据源配置 spring.datasource.url=jdbc:mysql://localhost:3306/school_db?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # MyBatis 配置 # 指定实体类所在的包 mybatis.type-aliases-package=com.example.demo.entity # 指定Mapper XML文件的位置 mybatis.mapper-locations=classpath:mapper/*.xml # 开启驼峰命名转换(下划线转驼峰) mybatis.configuration.map-underscore-to-camel-case=true ``` ### 3. 创建实体类 在包`com.example.demo.entity`下创建`Teacher`类: ```java package com.example.demo.entity; public class Teacher { private int id; private String name; private String subject; // gettersetter 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 getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } } ``` ### 4. 创建Mapper接口XML映射文件 首先,在包`com.example.demo.mapper`下创建`TeacherMapper`接口: ```java package com.example.demo.mapper; import com.example.demo.entity.Teacher; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface TeacherMapper { List<Teacher> findAllTeachers(); } ``` 然后,在`resources/mapper`目录下创建`TeacherMapper.xml`文件: ```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.example.demo.mapper.TeacherMapper"> <select id="findAllTeachers" resultType="Teacher"> SELECT id, name, subject FROM table2 </select> </mapper> ``` 注意:`namespace`属性必须对应Mapper接口的全限定名,`id`对应接口中的方法名。 ### 5. 创建Service层 在包`com.example.demo.service`下创建`TeacherService`接口: ```java package com.example.demo.service; import com.example.demo.entity.Teacher; import java.util.List; public interface TeacherService { List<Teacher> getAllTeachers(); } ``` 在包`com.example.demo.service.impl`下创建`TeacherServiceImpl`实现类: ```java package com.example.demo.service.impl; import com.example.demo.entity.Teacher; import com.example.demo.mapper.TeacherMapper; import com.example.demo.service.TeacherService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class TeacherServiceImpl implements TeacherService { @Autowired private TeacherMapper teacherMapper; @Override public List<Teacher> getAllTeachers() { return teacherMapper.findAllTeachers(); } } ``` ### 6. 创建Controller层 在包`com.example.demo.controller`下创建`TeacherController`: ```java package com.example.demo.controller; import com.example.demo.entity.Teacher; import com.example.demo.service.TeacherService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/api/teachers") public class TeacherController { @Autowired private TeacherService teacherService; @GetMapping public List<Teacher> getAllTeachers() { return teacherService.getAllTeachers(); } } ``` ### 7. 在启动类上添加@MapperScan 在Spring Boot的主启动类上添加`@MapperScan`注解,指定Mapper接口所在的包: ```java package com.example.demo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.demo.mapper") // 添加这行 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 这样,MyBatis的集成就完成了。启动应用,访问`http://localhost:8080/api/teachers`即可获取教师列表。 注意:如果之前配置了JPA,需要确保JPA的自动配置被禁用(通常移除JPA依赖后就不会自动配置了)。 ### 相关问题 1. 如何在MyBatis中实现动态SQL查询? 2. MyBatis如何实现分页查询? 3. 如何在Spring Boot中配置MyBatis的多数据源? 4. MyBatis的Mapper接口如何XML映射文件进行绑定? 5. MyBatis如何实现一对多、多对一的关系映射? 以上步骤详细说明了如何在Spring Boot项目中用MyBatis替代JPA进行数据库操作。如有问题,可参考MyBatis官方文档或Spring Boot集成MyBatis的相关资料[^1][^2][^3]。</think>### 在 Spring Boot 项目中集成 MyBatis 替代 JPA 的完整指南 #### 1. **移除 JPA 依赖并添加 MyBatis 依赖** 在 `pom.xml` 中替换依赖: ```xml <!-- 移除 JPA 依赖 --> <!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> --> <!-- 添加 MyBatis 依赖 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> <!-- 使用最新版本 --> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> ``` #### 2. **配置数据源 MyBatis** 在 `application.properties` 中配置: ```properties # 数据源配置 spring.datasource.url=jdbc:mysql://localhost:3306/school_db?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # MyBatis 配置 mybatis.mapper-locations=classpath:mapper/*.xml mybatis.type-aliases-package=com.example.demo.entity ``` #### 3. **创建实体类** ```java // src/main/java/com/example/demo/entity/Teacher.java public class Teacher { private Long id; private String name; private String subject; // Getters and Setters } ``` #### 4. **创建 Mapper 接口** ```java // src/main/java/com/example/demo/mapper/TeacherMapper.java @Mapper public interface TeacherMapper { List<Teacher> findAllTeachers(); Teacher findTeacherById(@Param("id") Long id); } ``` #### 5. **创建 XML 映射文件** ```xml <!-- src/main/resources/mapper/TeacherMapper.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.example.demo.mapper.TeacherMapper"> <resultMap id="teacherResultMap" type="Teacher"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="subject" column="subject"/> </resultMap> <select id="findAllTeachers" resultMap="teacherResultMap"> SELECT id, name, subject FROM table2 </select> </mapper> ``` #### 6. **创建 Service 层** ```java // src/main/java/com/example/demo/service/TeacherService.java @Service public class TeacherService { private final TeacherMapper teacherMapper; @Autowired public TeacherService(TeacherMapper teacherMapper) { this.teacherMapper = teacherMapper; } public List<Teacher> getAllTeachers() { return teacherMapper.findAllTeachers(); } } ``` #### 7. **创建 Controller** ```java // src/main/java/com/example/demo/controller/TeacherController.java @RestController @RequestMapping("/api/teachers") @CrossOrigin(origins = "http://localhost:8080") public class TeacherController { private final TeacherService teacherService; @Autowired public TeacherController(TeacherService teacherService) { this.teacherService = teacherService; } @GetMapping public ResponseEntity<List<Teacher>> getAllTeachers() { return ResponseEntity.ok(teacherService.getAllTeachers()); } } ``` #### 8. **添加 MyBatis 扫描配置** 在启动类添加注解: ```java @SpringBootApplication @MapperScan("com.example.demo.mapper") // 添加此注解 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` ### 关键配置说明: 1. **XML 映射文件位置**: `mybatis.mapper-locations=classpath:mapper/*.xml` 确保 MyBatis 能扫描到 XML 文件 2. **实体类别名**: `mybatis.type-aliases-package` 允许在 XML 中直接使用类名代替全限定名 3. **Mapper 接口扫描**: `@MapperScan` 注解替代了 JPA 的 Repository 自动扫描机制 4. **动态 SQL 支持**: MyBatis 支持在 XML 中使用动态 SQL 标签: ```xml <select id="findByCondition" resultMap="teacherResultMap"> SELECT * FROM table2 <where> <if test="name != null"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="subject != null"> AND subject = #{subject} </if> </where> </select> ``` ### JPA 的主要区别: | **特性** | **MyBatis** | **JPA** | |------------------|------------------------------------------|--------------------------------------| | **SQL 控制** | 完全手动编写,灵活性高 | 自动生成,灵活性低 | | **开发效率** | 需写 SQL 映射文件,效率较低 | 自动生成代码,开发效率高 | | **复杂查询支持** | 强大(支持动态 SQL) | 较弱(需结合 `@Query` 或 QueryDSL) | | **数据库兼容性** | 依赖 SQL 方言 | 通过 Hibernate 适配多种数据库 | | **学习曲线** | 需熟悉 SQL XML 配置 | 需理解 JPA 规范衍生查询语法 | ### 前端调用示例(Vue) ```vue <template> <div> <table> <tr v-for="teacher in teachers" :key="teacher.id"> <td>{{ teacher.name }}</td> <td>{{ teacher.subject }}</td> </tr> </table> </div> </template> <script> import axios from 'axios'; export default { data() { return { teachers: [] }; }, mounted() { axios.get('http://localhost:8080/api/teachers') .then(response => { this.teachers = response.data; }) .catch(error => { console.error('获取教师数据失败:', error); }); } }; </script> ``` ### 常见问题解决: 1. **Mapper 接口未注入**: 检查 `@MapperScan` 包路径是否正确,或直接在 Mapper 接口添加 `@Mapper` 注解 2. **XML 文件未加载**: 确认 `application.properties` 中 `mybatis.mapper-locations` 路径匹配 3. **驼峰命名转换**: 在配置中添加: ```properties mybatis.configuration.map-underscore-to-camel-case=true ``` 4. **事务管理**: 在 Service 方法添加 `@Transactional` 注解支持事务 MyBatis 提供了比 JPA 更精细的 SQL 控制能力,特别适合需要复杂查询优化或遗留数据库集成的场景[^1][^2]。其核心优势在于将 SQL Java 代码解耦,通过 XML 配置实现灵活的数据库操作[^3]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值