本系列共涉及4个框架:Sping,SpringBoot,Spring MVC,Mybatis。
博客涉及框架的重要知识点,根据序号学习即可。
目录
本系列共涉及4个框架:Sping,SpringBoot,Spring MVC,Mybatis。
博客涉及框架的重要知识点,根据序号学习即可。
1、回顾JDBC
1.1JDBC步骤
1.2具体实现
2、MyBatis入门
2.1什么是MyBatis
2.2MyBatis操作数据库的步骤
3、MyBatis增删改查
4、MyBatis的两种方式
4.1 注解方式
4.2 XML方式
4.3两者方式哪种更好?
1、回顾JDBC
1.1JDBC步骤
(1)创建数据库连接池DataSource
(2)通过DataSource获取数据库连接Connection
(3)编写要执行带?占位符的SQL语句
(4)通过Connection及SQL创建操作命名对象Statement
(5)替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
(6)使用Statement执行SQL语句
(7)查询操作:返回结果集ResultSet,更新操作:返回更新的数量
(8)处理结果集
(9)释放资源
1.2具体实现
package edu.fanhuiling;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class SimpleJdbcOperation {private final DataSource dataSource;public SimpleJdbcOperation(DataSource dataSource) {this.dataSource = dataSource;}/** 添加一本书* */public void addBook(){Connection connection=null;PreparedStatement stmt=null;try{//获取数据库连接connection =dataSource.getConnection();//创建语句stmt=connection.prepareStatement("insert into books(book_name,book_author,book_id)");//参数绑定stmt.setString(1,"Spring");stmt.setString(2,"Boot");stmt.setString(3,"123456789");//执行语句stmt.execute();} catch (SQLException e) {//处理异常信息throw new RuntimeException(e);}finally {//清理资源try{if(stmt!=null) stmt.close();if(connection!=null) connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}/** 更新一本书* */public void updateBook(){Connection connection=null;PreparedStatement stmt=null;try{//获取数据库连接connection =dataSource.getConnection();//创建语句stmt=connection.prepareStatement("update books set book_author=? where book_id =?;");//参数绑定stmt.setString(1,"张三");stmt.setString(2,"123456789");//执行语句stmt.execute();} catch (SQLException e) {//处理异常信息throw new RuntimeException(e);}finally {//清理资源try{if(stmt!=null) stmt.close();if(connection!=null) connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}/** 查询一本书* */public void queryBook(){Connection connection=null;PreparedStatement stmt=null;ResultSet rs=null;Book book=null;try{//获取数据库连接connection =dataSource.getConnection();//创建语句stmt=connection.prepareStatement("select book_name,book_author,book_id ftom books");//参数绑定stmt.setString(1,"123456789");//执行语句stmt.executeQuery();if(rs.next()){book = new Book();book.setBookName(rs.getString("book_name"));book.setBookAuthor(rs.getString("book_author"));book.setBookId(rs.getString("book_id"));}} catch (SQLException e) {//处理异常信息throw new RuntimeException(e);}finally {//清理资源try{if(rs!=null) rs.close();if(stmt!=null) stmt.close();if(connection!=null) connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}
}
能清楚的看出,整个过程是十分繁琐的,某些操作步骤还会重复书写,接下来就让我们来看看更简单、更方便的操作数据库——MyBatis!!!
2、MyBatis入门
2.1什么是MyBatis
(1)MyBatis是一款优秀的持久层框架,主要是用于简化JDBC的开发,来完成程序与数据库交互的框架。也可以理解为是一个更简单的操作和读取数据的工具。【持久层:值得就是持久化操作的层级,通常指数据库访问层(dao),是用来操作数据库的】
(2)MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到了GitHub。
2.2MyBatis操作数据库的步骤
(1)创建SpringBoot工程、数据库准备等等前置工作
(2)引入MyBatis的相关依赖,配置MyBatis
application.properties配置文件:
①注意数据库链接、账号、密码的更改
②如果使用MySQL是5.x之前的使用的是“com.mysql.jdbc.Driver”,如果是大于5.x使用的是“com.mysql.cj.jdbc.Driver”
#热部署生效
spring.devtools.restart.enabled=true
#设置重启目录
spring.devtools.restart.additional-paths=src/main/java
# 指定时区 避免因时区差异而导致的日期时间解析错误
spring.jackson.time-zone=Asia/Shanghai
#设置 cLasspath 目录下的WEB-INF文件夹内容修改不重启(有静态资源才需要)(需要修改成对应值)
spring.devtools.restart.exclude=static/**# 数据库驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库链接(需要修改成对应值)
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
# 数据库账号(需要修改成对应值)
spring.datasource.username=root
# 数据库密码(需要修改成对应值)
spring.datasource.password=1234
# 配置 mybatis 的日志,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 开启 mybatis 的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true
# 配置 mybatis 的映射文件路径(需要修改成对应值)
mybatis.mapper-locations=classpath*:mapper/*.xml
# 自动为包下所有Java类注册类型别名(需要修改成对应值)
mybatis.type-aliases-package=edu.xxxx.pojo
(3)编写SQL语句
(4)测试
3、MyBatis增删改查
(1)MyBatis的持久层接口规范一般都叫做XxxMapper
(2)案例:【目前不必掌握标签的具体意思,只需了解Mapper接口与Mapper.xml文件之间的关联,下一篇文章会讲解重点标签的含义】
为什这三个Mapper接口没有加注解@Mapper呢?因为已经在启动类加了@MapperScan扫描的路径了
①Account接口与xml实现
a、AccountMapper.class
import org.fanhuiling.pojo.Account;import java.util.List;public interface AccountMapper {//查询账号Account getAccount(String account);//添加账号void insertAccount(Account account);//查询学生的详细信息List<Account> getAccount();
}
b、AccountMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.fanhuiling.mapper.AccountMapper"><!--useGeneratedKeys="" :表示使用数据库的自增主键keyProperty="" :将数据库的自增主键与实体类的属性绑定parameterType="":指定传入的类型一般情况下:MyBatis能自动推断--><!--添加账号--><insert id="insertAccount" useGeneratedKeys="true" keyProperty="id" parameterType="Account">insert into account(account,password,role,create_by,create_time)values(#{account},#{password},#{role},#{createBy},#{createTime})</insert><!--查询学生的详细情况 两个表--><!--resultType 能与数据库对应的Java对象resultMap 能映射到Java对象--><select id="getAccount" resultMap="AccountWithDetails">select a.id,a.account,s.name,s.gender,s.birthday from account as a,student as s where a.account=s.id</select><!--id:用于映射的唯一标识符 主键column: 查询结果集中的数据库中的列名property java对象的属性名result:用于映射其他字段association建立一对一的关系--><resultMap id="AccountWithDetails" type="Account"><id column="id" property="id" /><result column="account" property="account"/><association property="studentDetails" javaType="Student"><id column="account" property="id"/><result column="name" property="name"/><result column="gender" property="gender"/><result column="birthday" property="birthday"/></association></resultMap></mapper>
②Student接口与xml实现
a、StudentMapper.class
import org.apache.ibatis.annotations.Mapper;
import org.fanhuiling.pojo.Student;import java.util.List;@Mapper
public interface StudentMapper {//查询所有对象List<Student> getAll();//根据id查询Student getById(String id);//根据姓名长度和性别查询List<Student> getByCondition(Integer len,Integer gender);//新增学生void insertStudent(Student student);//更新信息void updateStudent(Student student);//查询学生信息(带有性别名称)List<Student> getAllWithGender();//查询学生的所有成绩Student getStudentScoreById(String id);
}
b、studentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.fanhuiling.mapper.StudentMapper"><!--<sql>标签:定义可重用的sql片段<include>标签:通过属性refid,指定包含的sql片段<if>标签:用于判断条件是否成立,使用test属性来判读,如果为true,则拼接<where>标签:只在有子元素的情况下才会插入where子句,如果where不成立,则去掉where<set>标签:动态的在首行插入set关键字,并删除多余的逗号<foreach>--><sql id="commonSelect">select id,name,gender,birthday from student</sql><!--查询所有学生--><select id="getAll" resultType="org.fanhuiling.pojo.Student"><include refid="commonSelect"></include><!--select id,name,gender,birthday from student--></select><!--根据id查询学生--><select id="getById" resultType="org.fanhuiling.pojo.Student"><include refid="commonSelect"></include>where id=#{id}</select><!--根据条件查询学生--><select id="getByCondition" resultType="org.fanhuiling.pojo.Student"><include refid="commonSelect"></include><where><if test="len!=null">CHAR_LENGTH(student.name)=#{len}</if><if test="gender!=null">and gender=#{gender}</if></where></select><!-- 插入学生信息 --><insert id="insertStudent">insert into student(id, name, gender, birthday, create_by, create_time)values(#{id}, #{name}, #{gender}, #{birthday}, #{createBy}, #{createTime})</insert><!-- 更新学生信息 --><update id="updateStudent">update student<set><if test="name != null"> name = #{name},</if><if test="gender != null"> gender = #{gender},</if><if test="birthday != null"> birthday = #{birthday},</if><if test="updateBy != null"> update_by = #{updateBy},</if><if test="updateTime != null"> update_time = #{updateTime}</if></set>where id = #{id}</update><select id="getAllWithGender" resultMap="StudentWithGender">select s.id,s.name,g.id as gid,g.name as gname,s.birthday from student as s JOIN gender as g on g.id =s.gender </select><resultMap id="StudentWithGender" type="Student"><id column="id" property="id" /><result column="name" property="name"/><result column="birthday" property="birthday"/><association property="genderDetails" javaType="Gender"><id column="gid" property="id"/><result column="gname" property="name"/></association></resultMap><select id="getStudentScoreById" resultMap="StudentWithScore">select s.id as sid,s.name as sname,c.name as cname,sc.score from score as sc,student as s,course as c where s.id =#{id} sc.student_id=s.id and sc.course_id=c.id</select><resultMap id="StudentWithScore" type="Student"><id column="sid" property="id" /><result column="sname" property="name"/><collection property="scores" ofType="Score"><result column="score" property="score"/><result column="cname" property="course.name"/><!-- <association property="course" javaType="Course"><result column="cname" property="name"/></association><association property="student" javaType="Student"><result column="sname" property="name"/></association>--></collection></resultMap></mapper>
③ Score接口与xml实现
a、ScoreMapper.class
import org.fanhuiling.pojo.Score;
import java.util.List;public interface ScoreMapper {//新增成绩void insertScore(Score score);//根据id删除成绩void deleteById(Integer id);//批量删除void deleteByIds(List<Integer> ids);
}
b、ScoreMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.fanhuiling.mapper.ScoreMapper"><insert id="insertScore" useGeneratedKeys="true" keyProperty="id" parameterType="Score">insert into score(id,student_id,course_id,score,create_by,create_time)values(#{id},#{studentId},#{courseId},#{score},#{createBy},#{createTime})</insert><delete id="deleteById">delete from score where id = #{id}</delete><delete id="deleteByIds">delete from score where id in<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete><select id="getAllWithName" resultMap="ScoreWithName">select sc.id,s.name as sname,c.name as cname,sc.score from score as sc,student as s,course as c where sc.student_id=s.id and sc.course_id=c.id</select><resultMap id="ScoreWithName" type="Score"><id column="id" property="id" /><result column="score" property="score"/><association property="student" javaType="Student"><result column="sname" property="name"/></association><association property="course" javaType="Course"><result column="cname" property="name"/></association></resultMap></mapper>
(3)测试代码
测试类上添加了注解@SpringBootTest,该测试类在运行时,就会自动加载Spring的运行环境。注解@Autowired可以注入我们要测试的类,这样就可以进行测试了
import org.fanhuiling.mapper.AccountMapper;
import org.fanhuiling.mapper.ScoreMapper;
import org.fanhuiling.mapper.StudentMapper;
import org.fanhuiling.pojo.Account;
import org.fanhuiling.pojo.Score;
import org.fanhuiling.pojo.Student;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;@SpringBootTest
class ApplicationTests {@AutowiredStudentMapper studentMapper;@AutowiredAccountMapper accountMapper;@AutowiredScoreMapper scoreMapper;@Testvoid testGetAll() {//查询所有学生List<Student> students=studentMapper.getAll();System.out.println(students);}@Testvoid testGetById() {//根据id查询学生Student student=studentMapper.getById("12138");System.out.println(student);}@Testvoid testGetByCondition() {//根据条件查询学生List<Student> student=studentMapper.getByCondition(null,null);System.out.println(student);}@Testvoid testInsertAccount(){//新增账号Account account=new Account();account.setAccount("12143");account.setPassword("123456");account.setRole(1);account.setCreateBy(1);LocalDateTime now=LocalDateTime.now();account.setCreateTime(now);accountMapper.insertAccount(account);}@Testvoid testInsertStudent(){Student student =new Student();student.setId("12145");student.setName("陆展播");student.setGender(1);student.setBirthday(LocalDate.of(2002,10,24));student.setCreateBy(1);LocalDateTime now=LocalDateTime.now();student.setCreateTime(now);studentMapper.insertStudent(student);}@Testvoid testInsertScore(){Score score=new Score();score.setStudentId("12143");score.setCourseId("104");score.setScore(87);score.setCreateBy(1);LocalDateTime now=LocalDateTime.now();score.setCreateTime(now);scoreMapper.insertScore(score);}@Testvoid testUpdateStudent(){Student student=new Student();student.setId("12141");student.setName("张益达");student.setUpdateBy(1);LocalDateTime now=LocalDateTime.now();student.setUpdateTime(now);studentMapper.updateStudent(student);}@Testvoid testDeleteById(){scoreMapper.deleteById(32);}@Testvoid testDeleteByIds(){List<Integer> ids= Arrays.asList(33,34,35);scoreMapper.deleteByIds(ids);}@Testpublic void testGetAccount(){List<Account> accounts=accountMapper.getAccount();System.out.println(accounts);}@Testpublic void testGetAllWithGender(){List<Student> students=studentMapper.getAllWithGender();for(Student student:students)System.out.println(student);}}
(4)这里的重点不是编写代码,也不是编写测试代码,重点是理解XxxMapper接口对应XxxMapper.xml文件之间的关联与各自的作用,XxxMapper接口只提供方法定义,不具体实现与数据库的交互,而XxxMapper.xml才是编写SQL语句的地方!!!当然,除了XML方式还有注解的方式可以与数据库建立连接,数据交互。
4、MyBatis的两种方式
4.1 注解方式
(1)@Select()、@Insert()、@Update()、@Delete()
(2)这四个注解就可以直接写在XxxMapper接口中方法前面,括号里面直接写SQL语句即可
(3)小例子
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.fanhuiling.mybatis.pojo.Student;import java.util.List;@Mapper
public interface StudentMapper {//查询全部学生方法@Select("select * from student")public abstract List<Student> list();/** 根据id查询学生* */@Select("select * from student where id=#{id}")Student getById(String id);/** 根据姓氏查询* */@Select("select * from student where name like concat(#{lastName},'%')")List<Student> getByLastName(String lastName);}
4.2 XML方式
(1)mapper模版:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace=""></mapper>
(2)上述3、MyBatis增删改查的例子就是使用的XML方式
4.3两者方式哪种更好?
这个取决于你所在的开发团队,没有明确答案。我个人更偏向于XML方式,因为SQL语句与编写的java逻辑分开了!!!更容易理解代码