本文将介绍如何在springboot中连接mysql数据库,并介绍操作数据库的方式,spring jpa。本文是建立在已经学会如何构建springboot项目的基础上的。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
上面这段代码要加在《dependencys>这组标签里面,学过html的应该大致理解它的意思。
spring.datasource.url=jdbc:mysql://localhost:3306/forum?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
spring.datasource.username=root(根据你的MySQL用户名来填,一般都是root)
spring.datasource.password=你的密码
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true //表示在控制台打印出执行的相关sql语句
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。值得注意的是,JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,其中就包括了Spring与EJB3.0的开发团队。
本来我是想用hibernate的,但是它的hibernateTamplate 已经被废除了。而jpa的使用又和hibernate非常类似,所以直接学习并使用了jpa。
先讲一下为什么要编写实体类。
我们编写的实体类其实就是为了和数据库的表形成一一映射的关系,这样实体里的每一个变量都与表格的每个字段相对应。我们在java中直接操作实体类里的对象,其实也等价于在操作数据库里的相应字段。
下面以一个例子来介绍如何编写实体类。
假定现在数据库里面有一张user表,表里有userid,userName,password等这些字段。
那么我现在要为这张表编写一个实体类,应该如何实现?
直接看下面的代码和注释。
package com.example.demo.domain;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* @ClassName User
* @Description TODO
* @Auther ydc
* @Date 2019/1/7 19:44
* @Version 1.0
**/
@Entity //这是实体类的注解,必须要注明,表明这是一个实体类,关于springboot的注解,这里不再做深入介绍,先学会如何用,以后会介绍具体原理。
@Table(name = "user") //指定对应的数据库表
public class User extends BaseDomain implements Serializable {
//BaseDomain是我写的一个基类,现在可以先不管。
//implements Serializable 是为了实现序列化,原则上每一个实体类都需要序列化
//下面定义的一些常量可以先不管
public static final int user_locked = 1; //用户被锁定
public static final int user_unlocked = 0; // 用户未被锁定
public static final int user_normal=0;//普通用户
public static final int user_Admin = 1; //版块管理员
public static final int user_super_admin=2; //超级管理员
@Id //使用Id注解,表明这是主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //主键生成策略是自增型
@Column(name = "user_id") //对应数据库的主键名
private int userId;
//除了主键需要特殊声明以外,其他的只需要声明对应的列就行,注意name=""必须是数据库里面的字段名称,否则会报错
@Column(name = "user_name")
private String userName;
@Column(name="password")
private String password;
@Column(name = "credit")
private int credits;
@Column(name = "grade")
private String grade;
@Column(name = "academy")
private String academy;
@Column(name = "user_type")
private int user_type;
@Column(name = "locked")
private int locked;
@Column(name = "photo")
private String photo;
@Column(name = "last_ip")
private String lastIp;
@Column(name = "last_visit")
private Date lastVisit;
@Column(name = "signature")
private String signature;
@Column(name = "backPicture")
private String backPicture;
@Column(name = "email")
private String email;
//manyToMany是hibernate的一种写法,它表明当前的user这个表和另一个表是多对多的关系,利如学生和教室就是一个多对多的关系。具体参数含义可以直接百度一下,也可以先不管,因为这不重要,你只需要先知道可以这么用就行,需要的时候,直接查就行。
@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.EAGER)
@JoinTable(name = "board_manager",joinColumns = {@JoinColumn(name = "user_id")},inverseJoinColumns = {@JoinColumn(name = "board_id")})
private Set<Board> manBoards =new HashSet<Board>();
public Set<Board> getManBoards() {
return manBoards;
}
//下面的get/set方法直接右键generate就可以生成,为了方便,还是都生成一下吧
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getBackPicture() {
return backPicture;
}
public void setBackPicture(String backPicture) {
this.backPicture = backPicture;
}
public String getPhoto() {
return photo;
}
public int getUserId() {
return userId;
}
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
public int getCredits() {
return credits;
}
public String getGrade() {
return grade;
}
public String getAcademy() {
return academy;
}
public int getUser_type() {
return user_type;
}
public int getLocked() {
return locked;
}
public void setUserId(int userId) {
this.userId = userId;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
public void setCredits(int credits) {
this.credits = credits;
}
public void setGrade(String grade) {
this.grade = grade;
}
public void setAcademy(String academy) {
this.academy = academy;
}
public void setUser_type(int user_type) {
this.user_type = user_type;
}
public void setLocked(int locked) {
this.locked = locked;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getLastIp() {
return lastIp;
}
public void setLastIp(String lastIp) {
this.lastIp = lastIp;
}
public Date getLastVisit() {
return lastVisit;
}
public void setLastVisit(Date lastVisit) {
this.lastVisit = lastVisit;
}
//实体类为了测试方便需要提供有参数的构造函数和无参数构造函数,直接右键generate就行
public User(String userName, String password, int credits, String grade, String academy, int user_type, int locked, String photo, String lastIp, Date lastVisit) {
this.userName = userName;
this.password = password;
this.credits = credits;
this.grade = grade;
this.academy = academy;
this.user_type = user_type;
this.locked = locked;
this.photo = photo;
this.lastIp = lastIp;
this.lastVisit = lastVisit;
}
public User() {
}
}
先讲一下Dao层的作用,一般我们开发java web都是按MVC模式进行开发的,因为这样分层开发可以让开发更简单有效。而Dao层则是实现数据库与后端交互的桥梁。
下面通过代码来讲解Dao层。
package com.example.demo.dao;
import com.example.demo.domain.User;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* @ClassName UserDao
* @Description TODO
* @Auther ydc
* @Date 2019/1/7 20:26
* @Version 1.0
**/
//jpa已经为我们封装好了大量的sql语句,我们先继承一下JpaRepository<>里面的两个参数分别填写实体类和主键的类型(Long和integer都行)
public interface UserDao extends JpaRepository<User,Long> {
//findByUserName这个函数将会被解析成sql语句,select * from User where username=userName。
User findByUserName(String userName);
//同理findByUserId也会被解析成对应的sql语句
User findByUserId(int userId);
@Override
//Page<>是jpa为我们封装好的分页类,用于实现页面的分页效果
Page<User> findAll(Pageable pageable);
Page<User> findByUserNameLike(String userName,Pageable pageable);
//findByUserNameLike 是实现模糊查询的方式,在传入的参数userName中,需要我们设定好占位符 % .
List<User> findByUserNameLike(String userName);
//jpa没有提供更新语句,所以更新语句需要我们自己编写,语法格式和sql非常类似,不过注意我们要直接对实体类对象进行操作,具体写法参照下面的来就行。
//一般来说,有更新语句还需要提供@Transactional事物注解,但是在实践的项目中,我们不直接使用Dao层函数,而是新建一个service层,所以注解我直接加在了Service类里面。(注意,如果想直接使用dao层的更新语句,则必须在@Modifying前面加上@Transactional)
@Modifying
@Query(value = "update User as u set u.password=:password where u.userId=:id")
//=:password 其中 : 是占位符的意思,我们通过传入的参数,利用@Param("password") 就可以将我们想要更新的参数传给sql语句了。
void updatePasswordById(@Param("password") String password, @Param("id") int id);
@Modifying
@Query(value = "update User as u set u.user_type=:utype where u.userId=:id")
void updateUserTypeById(@Param("utype")int type,@Param("id") int id);
@Modifying
@Query(value = "update User as u set u.grade=:grade where u.userId=:id")
void updateUserGradeById(@Param("grade") String grade,@Param("id") int id);
@Modifying
@Query(value = "update User as u set u.academy=:academy where u.userId=:id")
void updateUserAcademyById(String academy,int id);
@Modifying
@Query(value = "update User as u set u.locked=:lock where u.userId=:id")
void updateUserLockedById(@Param("lock") int sta,@Param("id") int id);
@Modifying
@Query(value = "update User as u set u.credits = :credits where u.userId=:id")
void updateUserCreditById(@Param("credits") int credit,@Param("id") int id);
@Modifying
@Query(value = "update User as u set u.photo = :photo where u.userId=:id")
void updateUserPhoto(@Param("photo") String photo,@Param("id") int id);
@Modifying
@Query(value = "update User as u set u.signature=:signature where u.userId=:id")
void updateUserSignature(@Param("signature") String signature,@Param("id") int id);
@Modifying
@Query(value = "update User as u set u.userName=:name where u.userId=:id")
void updateUserName(@Param("name") String name,@Param("id") int id);
}
前面介绍了查找和更新,插入还没有写。其实插入很简单,jpa已经封装好了sava函数,需要传一个实体类对象进去,这样就完成保存了。
至于删除函数,jpa也提供了解析语句,将findBy… 的find 换成delete就行。这里不再详细讲解。
int page=1,size=10;
Sort sort = new Sort(Direction.DESC, "UserId");
Pageable pageable = new PageRequest(page, size, sort);
//意思是将数据库里的数据分页,每页10条数据,我现在需要第1页的数据,这样就会给我们返回第1页的10条数据
findALL(pageable);
springboot为我们提供了专门的测试文件test。
打开test目录,你可以直接在…applicationTest里进行测试,也可以新建java类来测试,新建java类后,需要注解
@RunWith(SpringRunner.class)
@SpringBootTest
下面我直接给出测试Userdao的代码和注释。
package com.example.demo.daoTest;
import com.example.demo.dao.*;
import com.example.demo.domain.*;
import com.example.demo.service.LoginLogService;
import com.example.demo.service.imp.BoardServiceImp;
import com.example.demo.service.imp.LoginLogServiceImp;
import com.example.demo.service.imp.TopicServiceImp;
import com.example.demo.service.imp.UserServiceImp;
import org.assertj.core.error.ShouldBeAfterYear;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
/**
* @ClassName LoginDaoTest
* @Description TODO
* @Auther ydc
* @Date 2019/1/8 10:18
* @Version 1.0
**/
@RunWith(SpringRunner.class)
@SpringBootTest
public class LoginDaoTest {
//利用spring注解,我们就可以直接使用userDao了,想要了解注解的知识,可以到我之前的博客里看。
@Autowired
private UserDao userDao;
@Test
@Transactional //之所以加上@Transactional是因为,我直接使用了userDao,里面有update函数,需要事物注解。
public void updateTopic(){
userDao.findByUserName("ydc");//根据名字ydc去数据库里面查,之前我已经在数据库里面插入了数据。
}
}
###参考质料
jpa参考博客
Spring Data JPA 参考指南
spring框架IOC容器的理解