1. 准备数据库
新建数据库 bookmanager
,然后创建两张表:图书表 book
和 预约图书表 appointment
;
-- 建数据库
CREATE DATABASE `bookmanager`;
-- 创建图书表
CREATE TABLE `book` (
`book_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '图书ID',
`name` varchar(100) NOT NULL COMMENT '图书名称',
`number` int(11) NOT NULL COMMENT '馆藏数量',
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='图书表';
-- 插入数据
INSERT INTO `book`(`book_id`, `name`, `number`) VALUES (1, "Effective Java", 10),(2, "算法", 10),(3, "MySQL 必知必会", 10);
-- 创建预约图书表
CREATE TABLE `appointment` (
`book_id` int(11) NOT NULL COMMENT '图书ID',
`student_id` int(11) NOT NULL COMMENT '学号',
`appoint_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '预约时间' ,
PRIMARY KEY (`book_id`, `student_id`),
INDEX `idx_appoint_time` (`appoint_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='预约图书表';
2. 实体类编写
数据库准备好之后,就可以给对应表创建实体类,创建实体类之前,我们可以在 pom.xml
中引入 lombok
依赖,减少代码的编写;
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
2.1 Book.java
package com.cunyu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author : cunyu
* @version : 1.0
* @className : Book
* @date : 2020/7/23 15:53
* @description : Book 实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
private int bookId;
private String name;
private int number;
}
2.2 Appointment.java
package com.cunyu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author : cunyu
* @version : 1.0
* @className : Appointment
* @date : 2020/7/23 15:57
* @description : Appointment 实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Appointment {
private int bookId;
private int studentId;
private Date appointTime;
private Book book;
}
3. dao 接口类编写
3.1 BookDao.java
package com.cunyu.dao;
import com.cunyu.pojo.Book;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @InterfaceName : BookDao
* @Author : cunyu
* @Date : 2020/7/23 16:02
* @Version : 1.0
* @Description : Book 接口
**/
public interface BookDao {
/**
* @param bookId 图书 id
* @return 对应 id 的图书
* @description 根据图书 id 查找对应图书
* @date 2020/7/23 16:04
* @author cunyu1943
* @version 1.0
*/
Book queryById(@Param("bookId") int bookId);
/**
* @param offset 查询起始位置
* @param limit 查询条数
* @return 查询出的所有图书列表
* @description 查询所有图书
* @date 2020/7/23 16:08
* @author cunyu1943
* @version 1.0
*/
List<Book> queryAll(@Param("offset") int offset, @Param("limit") int limit);
/**
* @param bookId 图书 id
* @return 更新的记录行数
* @description 借阅后更新馆藏
* @date 2020/7/23 16:09
* @author cunyu1943
* @version 1.0
*/
int reduceNumber(@Param("bookId") int bookId);
}
3.2 AppointmentDao.java
package com.cunyu.dao;
import com.cunyu.pojo.Appointment;
import org.apache.ibatis.annotations.Param;
/**
* @InterfaceName : AppointmentDao
* @Author : cunyu
* @Date : 2020/7/23 16:03
* @Version : 1.0
* @Description : Appointment 接口
**/
public interface AppointmentDao {
/**
* @param bookId 图书 id
* @param studentId 学生 id
* @return 插入的行数
* @description 插入预约图书记录
* @date 2020/7/23 16:13
* @author cunyu1943
* @version 1.0
*/
int insertAppointment(@Param("bookId") int bookId, @Param("studentId") int studentId);
/**
* @param bookId 图书 id
* @param studentId 学生 id
* @return
* @description 通过主键查询预约图书记录,并且携带图书实体
* @date 2020/7/23 16:16
* @author cunyu1943
* @version 1.0
*/
Appointment queryByKeyWithBook(@Param("bookId") int bookId, @Param("studentId") int studentId);
}
3.3 mapper 编写
编写好 dao
接口之后,并不需要我们自己去实现,MyBatis 会给我们动态实现,但是需要我们配置相应的 mapper
。在 src/main/resources/mapper
下新建 BookDao.xml
和 AppointmentDao.xml
,用于对应上面的 dao
接口;
3.3.1 BookDao.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.cunyu.dao.BookDao">
<select id="queryById" resultType="Book" parameterType="int">
SELECT book_id, name, number
FROM book
WHERE book_id = #{bookId}
</select>
<select id="queryAll" resultType="Book">
SELECT *
FROM book
ORDER BY book_id
LIMIT #{offset},#{limit}
</select>
<update id="reduceNumber">
UPDATE book
SET number = number - 1
WHERE book_id = #{bookId}
AND number > 0
</update>
</mapper>
3.3.2 AppointmentDao.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.cunyu.dao.AppointmentDao">
<insert id="insertAppointment">
<!-- ignore 主键冲突,报错 -->
INSERT ignore INTO appointment (book_id, student_id) VALUES (#{bookId}, #{studentId})
</insert>
<select id="queryByKeyWithBook" resultType="Appointment">
<!-- 告知MyBatis 把结果映射到 Appointment 的同时映射 Book 属性 -->
SELECT
appointment.book_id,
appointment.student_id,
appointment.appoint_time,
book.book_id "book.book_id",
book.`name` "book.name",
book.number "book.number"
FROM
appointment
INNER JOIN book ON appointment.book_id = book.book_id
WHERE
appointment.book_id = #{bookId}
AND appointment.student_id = #{studentId}
</select>
</mapper>
4. 测试
经过 准备数据库 -> 实体类编写 -> 接口类编写 -> mapper 配置 这一套流程之后,我们就可以进行模块化测试了,看看我们的接口是否成功实现。
4.1 BookDaoTest.java
package com.cunyu.dao;
import com.cunyu.pojo.Book;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
/**
* @author : cunyu
* @version : 1.0
* @className : BookDaoTest
* @date : 2020/7/23 18:02
* @description : BookDao 测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring/spring-*.xml")
public class BookDaoTest {
// 自动注入
@Autowired
private BookDao bookDao;
@Test
public void testQueryById() {
int bookId = 1;
Book book = bookDao.queryById(bookId);
System.out.println("ID 对应的图书信息:" + book);
}
@Test
public void testQueryAll() {
List<Book> bookList = bookDao.queryAll(0, 3);
System.out.println("所有图书信息:");
for (Book book : bookList
) {
System.out.println(book);
}
}
@Test
public void testReduceNumber() {
int bookId = 3;
int update = bookDao.reduceNumber(bookId);
System.out.println("update = " + update);
}
}
运行两次测试后,数据库的结果如下图:
4.2 AppointmentDaoTest.java
package com.cunyu.dao;
import com.cunyu.pojo.Appointment;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author : cunyu
* @version : 1.0
* @className : AppointmentDaoTest
* @date : 2020/7/23 18:21
* @description : AppointmentDao 测试
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring/spring-*.xml")
public class AppointmentDaoTest {
@Autowired
AppointmentDao appointmentDao;
@Test
public void testInsertAppointment() {
int bookId = 2;
int studentId = 18301333;
int insert = appointmentDao.insertAppointment(bookId, studentId);
System.out.println("Insert = " + insert);
}
@Test
public void testQueryByKeyWithBook(){
int bookId = 2;
int studentId = 18301333;
Appointment appointment=appointmentDao.queryByKeyWithBook(bookId,studentId);
System.out.println(appointment);
System.out.println(appointment.getBook());
}
}
预约后,appointment
表中插入记录;
5. 总结
至此,我们做的工作总结下来主要有如下几点:
- 设计数据库
- 创建实体类
- 编写 dao 接口类
- 编写 dao 接口对应 mapper,交由 MyBatis 动态实现
- 对 dao 接口方法实现进行测试
好了,图书管理系统第一阶段到此就结束了,下一步我们就可以对其进行优化,并编写 service 层和 controller 层代码了,详情可见 图书管理系统实战(二)