这是Mybatis由浅入深的第2节,上文传送门:【Mybatis由浅入深 -01入门】
通过本文您将掌握:
- 基本的CRUD语句如何写?
- insert如何获得自增id值?
- #{}与${}的区别?
- @Param到底该怎么用? 什么时侯必须用,什么时侯可以不用
- SqlSessionFactory如何单例?
使用环境
以下为基础前置条件:请参考其它博文自行安装。
- JDK:1.8
- Maven: 3.6.3
- Mysql: 5.7 安装教程
创建Mysql测试表
代码语言:javascript复制CREATE TABLE `user` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`age` tinyint(1) UNSIGNED NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
insert into `user` VALUES (1,'天罡gg',18);
1、插入insert
1.1 接口方法
在UserMapper.java接口新增一个方法:
代码语言:javascript复制 int insert(User user);
1.2. 对应的xml映射文件
在UserMapper.xml中插入insert节点,一般指定id(像使用雪花算法等 )的插入是这样的:
代码语言:javascript复制 <insert id="insert" parameterType="com.tiangang.dao.po.User">
insert into user (id, name, age)
values (#{id}, #{name}, #{age})
</insert>
如果不指定id, 插入后如何获得自增id值?
代码语言:javascript复制 <insert id="insert" parameterType="com.tiangang.dao.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user (name, age)
values (#{name}, #{age})
</insert>
说明:现在一般公司都是遵循阿里规范,id是自增列,插入以后要拿到id,所以推荐做法就是在insert节点增加一个selectKey节点,在order=“after” 时将自增id值设置到keyProperty列。
面试常考点: #{} 是参数占位符, #{id}就是id的占位符,会解析为JDBC预编译语句, 可以防sql注入(就像使用JDBC的?一样); {} 是字符串替换,不防sql注入,在 SQL 语句中直接插入一个不转义的字符串,一般用在代替表名列名场景。 例如: 按列名排序 :select * from user order by {age}, 按任意列查询:select * from user where
1.3 单元测试
代码语言:javascript复制 @Test
public void insertTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行insert
User user = new User();
user.setName("天罡666");
user.setAge(28);
int rows = mapper.insert(user);
System.out.println("受影响行数:" rows);
System.out.println("新插入User:" user);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
} finally {
sqlSession.close();
}
}
插入成功截图:
2、修改update
2.1 接口方法
同理,在UserMapper.java接口新增一个方法:
代码语言:javascript复制 int updateById(User user);
2.2 对应的xml映射文件
同理,在UserMapper.xml中插入update节点
代码语言:javascript复制 <update id="updateById" parameterType="com.tiangang.dao.po.User">
update user
set name = #{name},
age = #{age}
where id = #{id}
</update>
2.3 单元测试
代码语言:javascript复制 @Test
public void updateByIdTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行update
User user = new User();
user.setId(2L);
user.setName("天罡666");
user.setAge(38);
int rows = mapper.updateById(user);
System.out.println("受影响行数:" rows);
System.out.println("修改后的User:" user);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
} finally {
sqlSession.close();
}
}
执行结果如下图:
3、删除delete
3.1 接口方法
同理,在UserMapper.java接口新增一个方法:
代码语言:javascript复制 int deleteById(Long id);
3.2 对应的xml映射文件
同理,在UserMapper.xml中插入delete节点
代码语言:javascript复制 <delete id="deleteById" parameterType="java.lang.Long">
delete from user
where id = #{id}
</delete>
3.3 单元测试
代码语言:javascript复制 @Test
public void deleteByIdTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行delete
int rows = mapper.deleteById(2L);
System.out.println("受影响行数:" rows);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
} finally {
sqlSession.close();
}
}
执行结果如下图:
4、查询select
为了演示需要,新插入User:User{id=3, name=‘天罡666’, age=28}
4.1 接口方法(5个必会的查询场景)
在UserMapper.java接口新增方法如下:
代码语言:javascript复制 // 必会查询场景1:查询1个结果, 返回单个User
User selectById(int id);
// 必会查询场景2:查询N个结果, 返回结果List
List<User> selectListByName(String name);
// 必会查询场景3:根据N个参数(@Param指定参数名),查询N个结果,返回结果List
List<User> selectListByNameAge(@Param("name") String name, @Param("gleAge") Integer gleAge);
// 必会查询场景4:使用${} 进行任意列查询。另外,多个参数未指定@Param的使用
List<User> selectByAnyOneColumn(String columnName, String symbol, String value);
// 必会查询场景5:使用${} 进行order by
List<User> selectAll(String orderBy);
4.2 对应的xml映射文件
在UserMapper.xml中插入5个select节点
代码语言:javascript复制 <select id="selectById" resultType="com.tiangang.dao.po.User">
select * from user where id = #{id}
</select>
<select id="selectListByName" resultType="com.tiangang.dao.po.User">
select * from user
where name like concat ('%', #{name},'%')
</select>
<select id="selectListByNameAge" resultType="com.tiangang.dao.po.User">
select * from user
where name like concat ('%', #{name},'%') and age>=#{gleAge}
</select>
<select id="selectByAnyOneColumn" resultType="com.tiangang.dao.po.User">
select * from user
where ${arg0} ${arg1} #{arg2}
</select>
<select id="selectAll" resultType="com.tiangang.dao.po.User">
select * from user order by ${orderBy}
</select>
4.3 单元测试
代码语言:javascript复制 @Test
public void selectByIdTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行select
User user = mapper.selectById(1);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
@Test
public void selectListByNameTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行select
List<User> userList = mapper.selectListByName("天罡");
System.out.println(userList);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
@Test
public void selectListByNameAgeTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行select
List<User> userList = mapper.selectListByNameAge("天罡", 1);
System.out.println(userList);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
@Test
public void selectByAnyOneColumnTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行select
List<User> userList = mapper.selectByAnyOneColumn("name", "=", "天罡666");
System.out.println(userList);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
@Test
public void selectAllTest() {
// 1. 打开SqlSession
SqlSession sqlSession = MyBatisManager.openSession();
try {
// 2. 得到UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 执行select
List<User> userList = mapper.selectAll("age");
System.out.println(userList);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
5、补充封装的MyBatisManager
细心的小伙伴可能已经发现多了一个MyBatisManager类,如果看了上文,就知道SqlSessionFactory应该是全局唯一的,所以我们将它封装到了MyBatisManager.getSqlSessionFactory方法中(使用单例模式),并向外提供了MyBatisManager.openSession,屏蔽了内部实现,使用方只需要每次调用openSession即可,你Get到了吗?
代码语言:javascript复制public class MyBatisManager {
private static volatile SqlSessionFactory sqlSessionFactory = null;
public static SqlSessionFactory getSqlSessionFactory() {
// double check 双重检查, 保证SqlSessionFactory全局只创建一次
if (sqlSessionFactory == null) {
synchronized (MyBatisManager.class) {
if (sqlSessionFactory == null) {
String resource = "mybatis-config.xml";
try {
Reader reader = Resources.getResourceAsReader(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return sqlSessionFactory;
}
public static SqlSession openSession() {
return getSqlSessionFactory().openSession();
}
}
6、本文全部源码
这节看似非常简单,实则非常考验基础,很多知识点相信有几年工作经验的人依然傻傻弄不清楚,
如有不到之处,敬请指正!
另外,源码中在单元测试类中CRUD做了简单的封装,新加了 UserMapperTest02Better.java,与UserMapperTest02.java测试功能一致,只是使用executeUserMapperMethod方法简化了代码,不作赘述,详细请见源码:https://download.csdn.net/download/scm_2008/86509214