mybatis初级映射
一 前言
系统学习知识请认准知识追寻者(同公众号),错过作者,你有可能要走好多弯路
经过第一篇的入门文章,小白们都对mybatis的搭建流程应该都很熟悉,这篇文章主讲的是如何使用mybatis实现数据库的增删改查,以及相关的标签属性、配置说明,可以说这篇文章是为你以后的学习和工作打下坚实基础文章,小白们要认真看,认真敲,下面是准备的sql语句。此文强到没朋友!!!!
CREATE TABLE `course` (
`courseName` varchar(255) DEFAULT NULL COMMENT '课程名称',
`coursePrice` decimal(10,2) DEFAULT NULL COMMENT '课程价格',
`courseId` int(11) NOT NULL AUTO_INCREMENT COMMENT '课程id',
PRIMARY KEY (`courseId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='课程';
INSERT INTO `mybatis`.`course`(`courseName`, `coursePrice`, `courseId`) VALUES ('java基础课', 500.00, 1);
INSERT INTO `mybatis`.`course`(`courseName`, `coursePrice`, `courseId`) VALUES ('javaWeb课程', 1000.00, 2);
二 pom.xml
引入的依赖跟上篇文章一致,这次我们会用到junit单元测试。
<dependencies>
<!-- mybatis support-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- log4j support -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- junit support -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- mysql support -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.5</version>
</dependency>
</dependencies>
三 log4j.properties
log4j.properties 放在 resource目录下,修改包名并配置日志级别为debug,用于打印sql;
log4j.rootLogger = info,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
## 注意改薄
log4j.logger.com.zszxz.mybatis.config.mapper = debug
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
四 实体
mybatis中经常使用到实体就是可以用作封装参数或者对返回的结果集进行映射到实体;
/**
* @Author lsc
* <p> </p>
*/
public class Course {
// 课程名称
private String courseName;
// 课程价格
private double coursePrice;
// 主键
private Long courseId;
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public double getCoursePrice() {
return coursePrice;
}
public void setCoursePrice(double coursePrice) {
this.coursePrice = coursePrice;
}
public Long getCourseId() {
return courseId;
}
public void setCourseId(Long courseId) {
this.courseId = courseId;
}
}
五 mapper配置
mybatis-config.xml 存放于resource目录下,用于配置mybatis;
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybaits配置 -->
<configuration>
<!-- 全局环境配置-->
<environments default="development">
<environment id="development">
<!-- 事物 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<!-- 数据库驱动 5.6以上版本使用com.mysql.cj.jdbc.Driver -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- 数据库路径 -->
<property name="url" value="jdbc:mysql://192.168.0.105:3306/mybatis"/>
<!-- 账号-->
<property name="username" value="root"/>
<!--密码 -->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 引入自定义mapper.xml 在resource 目录下 -->
<mappers>
<mapper resource="configMapper/CourseMapper.xml"/>
</mappers>
</configuration>
六 使用方法名称查询
6.1 mapper接口与mxl
这么注意命名空间与接口的关系,方法名与id的关系,返回值是类的全限定名;其中CourseMapper.xml文件是放在resource目录下configMapper中;
CourseMapper.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.zszxz.mybatis.config.mapper.CourseMapper">
<select id="getCourseList" resultType="com.zszxz.mybatis.config.entity.Course">
SELECT * FROM course
</select>
</mapper>
mapper接口
public interface CourseMapper {
/* *
* @Author lsc
* <p> 查询课程列表</p>
* @Param []
* @Return java.util.List<com.zszxz.mybatis.config.entity.Course>
*/
List<Course> getCourseList();
}
6.2查询测试
这边的@before注解是在每次执行测试类之前都会执行,固后面的查询测试将直接列出测试方法,不会重复@before注解下的方法;
@RunWith(JUnit4.class)
public class SelectTest {
SqlSession sqlSession = null;
// @Before 会在执行测试类之前执行该方法
@Before
public void before() throws IOException {
// 资源路径 resource目录下
String resource = "mybatis-config.xml";
// 配置mybatis获得输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//从 SqlSessionFactory 中获取 SqlSession
sqlSession= sqlSessionFactory.openSession();
}
/* *
* @Author lsc
* <p> 查询课程列表</p>
* @Param []
* @Return void
*/
@Test
public void testSelect(){
// 使用传入方法名查询形式
List<Course> getCourseList = sqlSession.selectList("getCourseList");
for (Course course : getCourseList){
System.out.println(course.getCourseName());
}
sqlSession.close();
}
}
6.3 测试结果
==> Preparing: SELECT * FROM course
[DEBUG] 2019-12-05 21:02:00,238 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Parameters:
[DEBUG] 2019-12-05 21:02:00,256 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
<== Total: 2
java基础课
javaWeb课程
七 使用获取接口方式查询
这种方式是主流方式,你不可能每次查询都输入一个方法名吧,很不现实,我们更倾向于面向对象方式直接调用方法获得想要的结果;
7.1 查询测试
测试结果和上次一致;
@Test
public void testSelect2(){
// 获得mapper的形式
CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
// 遍历打印课程
for (Course course : courseMapper.getCourseList()){
System.out.println(course.getCourseName());
}
sqlSession.close();
}
7.2 select标签属性说明
属性 | 说明 |
---|---|
id | 在命名空间中唯一的标识符,可以代表引用该sql |
parameterType | 入参的完全限定名或者别名,可选操作,默认未设置。 |
resultType | 返回值的期望类型的类的完全限定名或者别名,可以使用 resultType 或 resultMap,但不能同时使用 |
resultMap | 外部结果集映射配置,可以与实体字段映射;可以使用 resultType 或 resultMap,但不能同时使用 |
flushCache | 设置true会清口本地缓存和二级缓存,默认是false |
useCache | 设置为true会导致查询结果集保存至二级缓存,对于select默认是true |
timeout | 抛出异常前,驱动程序等待的最大毫秒数,默认未设置,依赖于驱动 |
fetchSize | 驱动程序每次批量返回行数,默认未设置 |
statementType | 设置STATEMENT,PREPARED 或 CALLABLE 。分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED |
resultSetType | 设置结果集类型,FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset)默认为设置 DEFAULT |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
resultOrdered | 嵌套查询语句中使用,设置为true,则sql执行结果为嵌套结果或者分组 |
resultSets | 在多个结果集情况下,会列出结果集名称,以逗号分隔 |
八 普通新增
8.1 mapper接口方法
/* *
* @Author lsc
* <p> 普通新增</p>
* @Param [course]
* @Return int
*/
int addCourse(Course course);
8.2 mxl语句
<insert id="addCourse" parameterType="com.zszxz.mybatis.config.entity.Course">
INSERT INTO course ( courseName, coursePrice ) VALUES ( #{ courseName },#{ coursePrice });
</insert>
8.3 测试
@Test
public void testInsert(){
// 创建入参实体 Course
Course course = new Course();
course.setCourseName("知识追寻者的心理课");
course.setCoursePrice(10000);
// 获得mapper
CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
// 调用添加课程方法
courseMapper.addCourse(course);
// 事物提交
sqlSession.commit();
// 关闭会话
sqlSession.close();
}
8.4 执行结果
可以看见我们用#{}在xml中达到了原生jdbc预编译后的结果每次进入都是以?占位符形式,有效防止sql注入问题;${}通常用在获取字段名称,表名,而非入参,否则会有sql注入风险。
[DEBUG] 2019-12-05 21:58:44,193 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Preparing: INSERT INTO course ( courseName, coursePrice ) VALUES ( ?,?);
[DEBUG] 2019-12-05 21:58:44,221 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Parameters: 知识追寻者的心理课(String), 10000.0(Double)
[DEBUG] 2019-12-05 21:58:44,224 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
<== Updates: 1
九 新增返回主键方式一
9.1 mapper接口方法
/* *
* @Author lsc
* <p> 新增数据并获得主键方式1</p>
* @Param [course]
* @Return int
*/
int addCourseAndGetIdbyGen(Course course);
9.2 mxl语句
在 <insert>
标签中 相比于 <select>
标签多出了3个属性。
useGeneratedKeys
为true,表示使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键。其适用于mysql 、 sqlServer这样有自增主键的数据库管理系统,默认是false;仅对 插入和更新操作有效。keyProperty
代表主键,mybaits会将主键赋值给这个列,这里我们配置的是实体字段courseId;希望赋值给多个列,默认是以逗号分开;默认是未设置;仅对 插入和更新操作有效。keyColumn
当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。我们这里必须设置,因为作者把 主键放在第三列了,不仔细看作者文章的小朋友等着出错把!默认是未设置;仅对 插入和更新操作有效。
<insert id="addCourseAndGetIdbyGen" parameterType="com.zszxz.mybatis.config.entity.Course" useGeneratedKeys="true" keyProperty="courseId" keyColumn="courseId">
INSERT INTO course ( courseName, coursePrice ) VALUES ( #{ courseName },#{ coursePrice });
</insert>
9.3 测试
小白们这里注意啊,获得插入的主键是从我们入参的Course实体属性中获得;
@Test
public void testInsertGetId1(){
Course course = new Course();
course.setCourseName("知识追寻者的课程1");
course.setCoursePrice(100000);
CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
courseMapper.addCourseAndGetIdbyGen(course);
//
System.out.println("返回的课程id: "+course.getCourseId());
sqlSession.commit();
sqlSession.close();
}
9.4 执行结果
[DEBUG] 2019-12-05 22:17:01,788 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Preparing: INSERT INTO course ( courseName, coursePrice ) VALUES ( ?,?);
[DEBUG] 2019-12-05 22:17:01,820 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Parameters: 知识追寻者的课程1(String), 100000.0(Double)
[DEBUG] 2019-12-05 22:17:01,822 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
<== Updates: 1
返回的课程id: 4
十新增返回主键方式二
10.1 mapper接口方法
/* *
* @Author lsc
* <p> 新增数据并获得主键方式2</p>
* @Param [course]
* @Return int
*/
int addCourseAndGetIdbyKey(Course course);
10.2 mxl语句
这里使用了 <selectKey>
标签做返回插入数据的主键,这种方式使用于具有主键自增的数据库管理系统,也使用于像oracle这样不具有主键自增的数据库管理系统,而且每种数据库管理系统支持的 <selectKey>
标签内容都不一样,但都大同小异,读者可以查阅数据库管理系统相关文档使用。需要注意的是 order 属性,由于mysql这种主键自增型数据库管理系统是语句插入后才能获得主键,固使用 after;如果是 oracle这种非自增型主键数据库管理系统,是语句插入之前主键就以及存在,固要设置属性为before;
<insert id="addCourseAndGetIdbyKey" parameterType="com.zszxz.mybatis.config.entity.Course">
INSERT INTO course ( courseName, coursePrice, courseId ) VALUES ( #{ courseName },#{ coursePrice },#{ courseId });
<selectKey resultType="long" order="AFTER" keyProperty="courseId">
SELECT LAST_INSERT_ID();
</selectKey>
</insert>
10.3 测试
代码很清秀,不用作者多余的注释了吧。
@Test
public void testInsertGetId2(){
Course course = new Course();
course.setCourseName("知识追寻者的课程2");
course.setCoursePrice(100000);
CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
courseMapper.addCourseAndGetIdbyGen(course);
//
System.out.println("返回的课程id: "+course.getCourseId());
sqlSession.commit();
sqlSession.close();
}
10.4 执行结果
[DEBUG] 2019-12-05 22:25:31,232 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Preparing: INSERT INTO course ( courseName, coursePrice ) VALUES ( ?,?);
[DEBUG] 2019-12-05 22:25:31,258 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Parameters: 知识追寻者的课程2(String), 100000.0(Double)
[DEBUG] 2019-12-05 22:25:31,261 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
<== Updates: 1
返回的课程id: 5
十一更新操作
更新相比于查询和插入,其相对简单;
11.1 mapper接口方法
/* *
* @Author lsc
* <p> </p>
* @Param [course]
* @Return int
*/
int updateCourse(Course course);
11.2 mxl语句
<update id="updateCourse" parameterType="com.zszxz.mybatis.config.entity.Course">
UPDATE course set courseName = #{courseName}, coursePrice = #{coursePrice}
WHERE courseId = #{courseId}
</update>
11.3 测试
@Test
public void testUpdate2(){
Course course = new Course();
course.setCourseName("知识追寻者的课程3");
course.setCoursePrice(1000);
course.setCourseId(5L);
CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
courseMapper.updateCourse(course);
sqlSession.commit();
sqlSession.close();
}
11.4 执行结果
[DEBUG] 2019-12-05 22:38:46,093 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Preparing: UPDATE course set courseName = ?, coursePrice = ? WHERE courseId = ?
[DEBUG] 2019-12-05 22:38:46,121 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Parameters: 知识追寻者的课程3(String), 1000.0(Double), 5(Long)
[DEBUG] 2019-12-05 22:38:46,124 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
<== Updates: 1
十二删除操作
删除操作和更新操作类似,没什么技巧难度;
12.1 mapper接口方法
/* *
* @Author lsc
* <p> </p>
* @Param []
* @Return int
*/
int deleteCourse(Long courseId);
12.2 mxl语句
<delete id="deleteCourse" parameterType="long">
DELETE FROM course WHERE courseId = #{courseId}
</delete>
12.3 测试
@Test
public void testDelte(){
CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
courseMapper.deleteCourse(1L);
sqlSession.commit();
sqlSession.close();
}
12.4 执行结果
[DEBUG] 2019-12-05 22:39:29,926 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Preparing: DELETE FROM course WHERE courseId = ?
[DEBUG] 2019-12-05 22:39:29,952 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
==> Parameters: 1(Long)
[DEBUG] 2019-12-05 22:39:29,955 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159)
<== Updates: 1