1. hibernate和mybatis的区别
一、两者最大的区别
针对简单逻辑,Hibernate与MyBatis都有相应的代码生成工具,可以生成简单基本的DAO层方法。
针对高级查询,MyBatis需要手动编写SQL语句,以及ResultMap,而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于流程。
二、开发难度对比
Hibernate的开发难度大于MyBatis,主要由于Hibernate比较复杂,庞大,学习周期比较长。
MyBatis则相对简单,并且MyBatis主要依赖于生气了的书写,让开发者刚进更熟悉。
三、sql书写比较
Hibernate也可以自己写sql来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性,不过Hibernate具有自己的日志统计。
MyBatis的sql是手动编写的,所以可以按照要求指定查询的字段,不过没有自己的日志统计,所以要借助Log4j来记录日志。
四、数据库扩展性计较
Hibernate与数据库具体的关联在XML中,所以HQL对具体是用什么数据库并不是很关心
MyBatis由于所有sql都是依赖数据库书写的,所以扩展性、迁移性比较差。
五、缓存机制比较
Hibernate的二级缓存配置在SessionFactory生成配置文件中进行详细配置,然后再在具体的表对象映射中配置那种缓存。
MyBatis的二级缓存配置都是在每个具体的表对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓冲机制,并且MyBatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。
两者比较
因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL,所以在使用二级缓存时如果出现脏数据,系统会报出错误提示。 而MyBatis在这一方面使用二级缓存时需要特别小心,如果不能完全去顶数据更新操作的波及范围,避免cache的盲目使用,否则,脏数据的出现会给系统的正常运行带来很大的隐患。
2.新建Springboot项目添加依赖
pom文件中依赖如下:
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.traffic</groupId>
<artifactId>trafficwarning</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>trafficwarning</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!--极光推送-->
<dependency>
<groupId>cn.jpush.api</groupId>
<artifactId>jpush-client</artifactId>
<version>3.2.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.2</version>
</dependency>
<!--MySQL依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<!-- maven项目中src源代码下的xml等资源文件编译进classes文件夹,
注意:如果没有这个,它会自动搜索resources下是否有mapper.xml文件,
如果没有就会报org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.pet.mapper.PetMapper.selectByPrimaryKey-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<!--将resources目录下的配置文件编译进classes文件 -->
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
重点来了application.properties的配置:
注:此时和mybatis 配置略有不同,除了常规数据源的配置外,还需要对hibernate的jap 进行设置,具体如下:
# 数据库访问配置
# 主数据源,默认的
#端口号
server.port=8085
#----------------------database-------------------------
spring.datasource.url = jdbc:mysql://localhost:3306/companytest?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username = name
spring.datasource.password = password
com.mysql.cj.jdbc.Driver= com.mysql.jdbc.Driver
#server.port=9090
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
spring.datasource.useGlobalDataSourceStat=true
#JPA Configuration:
spring.jpa.database=MYSQL
# Show or not log for each sql query
spring.jpa.show-sql=false
spring.jpa.generate-ddl=true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto=update
#spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
#spring.jpa.database=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto 的配置需要留意,如果配置了create,则每次重启服务会将连接的对接数据表进行情况,一般情况我们有update.
create: 每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
create-drop :每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。
validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
3.实体类注解应用
package com.example.springboothibernate.entity;
import javax.persistence.*;
/**
* springboot集成hibernate 实例
* @Entity用来标识这是一个实体类
* @Id hibernate的特征,必须要一个id不然会报错
* @Column(name = "sid") 用来跟表的字段做个映射,如果名字相同就不需要写
* @return
*/
@Entity
@Table(name="student")
public class Student {
@Id
@Column(name = "sId")
@GeneratedValue(strategy= GenerationType.AUTO)
private int sId;
@Column(name = "sName")
private String sName;
@Column(name = "classId")
private String classId;
public int getsId() {
return sId;
}
public void setsId(int sId) {
this.sId = sId;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
}
dao层代码
package com.example.springboothibernate.dao;
import com.example.springboothibernate.entity.Student;
import java.util.List;
import java.util.Optional;
import org.springframework.data.repository.CrudRepository;
public interface StudentMapper extends CrudRepository<Student,String> {
/**
* 新增学生
* @param student
* @return
*/
Student save(Student student);
/**
* 删除学生
* @param
*/
void deleteBysId(int sId);
/**
* 查询
* @return
*/
List<Student> findAll();
/**
* 查询单个
* @param
* @return
*/
Student findBysId(int sId);
}
Service and Impl
package com.example.springboothibernate.service;
import com.example.springboothibernate.entity.Student;
import org.springframework.stereotype.Service;
import java.util.List;
public interface StudentService {
/**
* 添加
*/
void insertStudent(Student student);
/**
* 删除
*/
void deleteStudent(int sId);
/**
* 修改
*/
void updateStudent(Student student);
/**
* 查询
*/
List<Student> getStudent();
/**
* 查询单个
*/
Student getStudentBysId(int sId);
}
package com.example.springboothibernate.serviceImpl;
import com.example.springboothibernate.dao.StudentMapper;
import com.example.springboothibernate.entity.Student;
import com.example.springboothibernate.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public void insertStudent(Student student) {
studentMapper.save(student);
}
@Override
@Transactional
public void deleteStudent(int sId) {
studentMapper.deleteBysId(sId);
}
@Override
public void updateStudent(Student student) {
studentMapper.save(student);
}
@Override
public List<Student> getStudent() {
return studentMapper.findAll();
}
@Override
public Student getStudentBysId(int sId) {
return studentMapper.findBysId(sId);
}
}
注意:
在进行对表的Delete需要在Service层上进行@Transaction注解,否则无法顺利执行,爆出如下异常
"timestamp": "2019-12-17T05:58:57.054+0000",
"status": 500,
"error": "Internal Server Error",
"message": "No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call",
"path": "/demo01/delete"
大概意思是:在需要事务的方法上,没有开启事务,结果就操作需要事务的方法比如保存,修改数据库数据方法。
修复方式也特别简单,在需要事务的方法上加入加上注解:@Transactional即可。
Controller
package com.example.springboothibernate.controller;
import com.example.springboothibernate.entity.Student;
import com.example.springboothibernate.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@RestController
@RequestMapping("/demo01")
public class HibernateController {
@Autowired
StudentService studentService;
/**
* 添加
* @return
*/
@RequestMapping("/insert")
public String insert(HttpServletRequest request, HttpServletResponse response){
int sId=Integer.parseInt(request.getParameter("sId"));
String sName=request.getParameter("sName");
String classId=request.getParameter("classId");
Student student = new Student();
student.setsId(sId);
student.setsName(sName);
student.setClassId(classId);
studentService.insertStudent(student);
return "SUCCESS";
}
/**
* 删除
* @param
* @return
*/
@RequestMapping("/delete")
public String delete(HttpServletRequest request, HttpServletResponse response){
int sId=Integer.parseInt(request.getParameter("sId"));
studentService.deleteStudent(sId);
return "SUCCESS";
}
/**
* 修改
* 修改跟添加调用的是同一个方法如果id相同就改变数据没有就创建数据
* @param student
* @return
*/
@RequestMapping("/update")
public String update(HttpServletRequest request, HttpServletResponse response){
Student student = new Student();
int sId=Integer.parseInt(request.getParameter("sId"));
String sName=request.getParameter("sName");
String classId=request.getParameter("classId");
student.setsId(sId);
student.setsName(sName);
student.setClassId(classId);
studentService.updateStudent(student);
return "SUCCESS";
}
/**
* 查询
* @return
*/
@RequestMapping("/getStudent")
public List<Student> getStudent(){
return studentService.getStudent();
}
/**
* 根据sid查询
* @param
* @sId
*/
@RequestMapping("/studentId")
public Student getStudentBysId(HttpServletRequest request, HttpServletResponse response){
int sId=Integer.parseInt(request.getParameter("sId"));
return studentService.getStudentBysId(sId);
}
}
以上只是简单的CRUD,剩下一对多和多对多将在后期进行更新。
你点的每一个赞,我都认真当成了喜欢