目录
前面实践篇我们讲了如何从零创建一个Mybatis项目,然后原理篇我们浅讲了一下Mybatis的实现原理及流程,今天,我们来详细讲一下Mybatis的语法规则。
我们就安照原理篇写的书写顺序,然后根据实例,来讲解一下Mybatis的语法规则。
1查询所有数据
现在,我们要查询User表中的所有数据
我们在UserDao.xml文件中写下如下的sql语句:
<select id="findAll" resultType="com.qcby.entity.User">
select * from user
</select>
即如下图所示:
说明:
第5行 namespace :写的是我们Userdao的地址,与相应的接口类进行连接
第7行 select:是查询关键字,表示语句是用来查询的,其他的比如删除,用delete;修改,用update;添加,用insert
第7行 id:是唯一标识符,可以理解为方法名,要与对应的接口类中的方法名相同(可以与相应的测试方法名不同)
第7行 resultType:指返回值类型,这里我们查询出来的是一条条user数据,所以用user对象来接收
现在,我们在接口类中写下如下内容:
public List<User> findAll();
即如下图所示:
说明:因为查询返回的是一条条user内容,所以我们用List<User>来接收返回值
现在,我们来写测试类:
public class UserTest {
private InputStream in = null;
private SqlSession session = null;
private UserDao mapper = null;
@Before //前置通知, 在方法执行之前执行
public void init() throws IOException {
//加载主配置文件,目的是为了构建SqlSessionFactory对象
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//通过SqlSessionFactory工厂对象创建SqlSesssion对象
session = factory.openSession();
//通过Session创建UserDao接口代理对象
mapper = session.getMapper(UserDao.class);
}
@After //@After: 后置通知, 在方法执行之后执行 。
public void destory() throws IOException {
//释放资源
session.close();
in.close();
}
/**
* 测试查询所有的方法
*/
@Test
public void findAll() throws IOException {
List<User> users = mapper.findAll();
for (User user:users) {
System.out.println(user.toString());
}
}
}
即如下图所示:
说明:
第19行:我们创建一个io对象in,并对in赋值null
第20行:创建一个sqlSession对象session,赋值null
第21行:创建接口代理对象,还是赋值null
第26行:利用io对象in,来加载sqlMapConfig.xml文件,使计算机可以读取mapper下的UserDao.xml文件
第28行:创建sqlSessionFactory对象,就是一个工厂,让工厂通过in来读取sqlMapConfig.xml文件
第30行:我们可以理解为打开工厂,并将其命名为session,也可以理解为第28行的factory是一个工厂模板,第30行是创建了一个实体化工厂对象,然后我们的一些操作是在这里进行的
第32行:通过session对象来创建UserDao接口代理对象。这里才是最关键的一步,因为这里出现了我们的代理对象(回想代理的基本思想)
第47行:创建User类型的列表users,通过代理对象来调用接口里面的findAll()方法
第48行:for循环,打印输出
第45行:@Test 表示这个一个测试方法,点击可以运行此方法
第23行:@Before 注解,表示下面的代码在Test之前运行
第35行:@After 注解,表示下面的代码在Test之后运行
第38行:关闭sqlSession工厂,释放资源
第39行:关闭io对象,释放资源
下面,我去配置一下sqlMapConfig.xml文件,如下图所示:
说明:
第20行:是对mapper下的xml文件的引用。
好了,现在让我们回到测试方法来点击测试一下:
当然,有点同学会出现这样的情况:
上面是几行红色的警告,不用担心,我的其他文章会教大家解决。
现在,我们的第一条sql语句就执行成功了。
2根据id进行查询
下面我们来书写根据id进行查询的sql语句
首先,在我们的UserDao.xml中写下如下语句:
<select id="findById" parameterType="java.lang.Integer" resultType="com.qcby.entity.User">
select * from user where id = #{id}
</select>
即如下图所示:
说明:
第11行 parameterType:指的是输入值的类型,可以理解为入参类型
第12行 id=#{id}:这里用的是#{},是用占位赋值的方式来拼接sql的,这是Mybatis参数注入的一种方式,后面会详细讲,暂时先记着这样用就行
下面,我们来写接口,如下图所示:
然后,我们来写测试方法:
@Test
public void findById(){
User user=mapper.findById(3);
System.out.println(user.toString());
}
即如下图所示:
然后,点击测试运行:
3.插入一条数据
老规矩,先写UserDao.xml文件中的方法,代码如下:
<insert id="insertUser" parameterType="com.qcby.entity.User">
insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
截图如下:
说明:
我们在写sql语句时,考虑的出参入参,是针对sql语句的,而不是针对接口中方法的。什么意思?以插入为例:插入数据,我们需要对数据赋值,这就是入参,但是插入的sql语句会返回什么?是一张表吗?不是;是一条数据吗?不是;是一个数子吗?不是;也就是说,当我们插入一条数据时,它是没有返回值的。所以,这里我们没有写出参,也就是resultType。但是换个角度想,我们执行这条插入语句时,会返回什么?Navicat会返回你插入的条数,也就是1。所以我们接口的返回参数类型就要定义为int型。
这里我们要区别:“我们查询 / 插入 / 删除 / 修改 一条语句时,需要什么?会返回什么?”根据这个,确定我们写sql语句时要定义的出参与入参。还有“当我们执行 查询 / 插入 / 删除 / 修改 语句时,会返回什么?”根据这个,可以在一些时候来确定我们写接口时定义返回参数的类型。这是比较绕的。我也是执行插入操作时才思考的。
下面,我们来看一下接口的书写(不给你们代码了,直接上图):
注意那个int,结合上面写的,思考一下。
下面看测试方法的书写:
@Test
public void insert(){
User user = new User();
user.setUsername("哈哈1");
int code = mapper.insertUser(user);
session.commit();
System.out.println(code);
}
截图如下:
说明:
第65行:这里的session.commit()是做session提交的。我们在执行修改操作时(增,删,改,三种)需要进行数据的提交。记住就行,原理我也不太清楚。
最后,看一下结果:
为了弄清那个出参与入参的东西,让我们直接在Navicat上运行一下插入操作,看下结果:
关于这个出入参,和接口方法返回值的定义,我们需要好好思考一下
4.获取插入数据的id
一样,先写UserDao.xml文件里面的方法,代码如下:
<insert id="insertGetId" parameterType="com.qcby.entity.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
写完后的截图如下:
说明:
第19行:和前面插入方法一样,不多讲
第20行:注意这里的关键字是“selectKey”,什么意思?查询关键字,表示这条语句就是查询关键字的; “keyProperty”表示你的关键字是什么,我们当初在设计表的时候,是将id设为关键字的,所以后面写“id”; “resultType”指的是返回值类型,前面讲过,不多说; “order”指的是顺序,即这条语句执行的顺序是什么,我们这里是在插入数据之后获取它的id的,所以这条语句的顺序是在插入语句之后执行。
第21行:算是一种固定写法吧,记住就行
第23行,插入语句,没啥好说的
然后,我们来写接口(不给代码,直接给图):
然后,我们来看一下测试方法(代码如下):
@Test
public void insertGetId(){
User user = new User();
user.setUsername("哈哈3");
int code = mapper.insertGetId(user);
//数据的修改,需要做session数据的提交
session.commit();
System.out.println(code); //code = 1
//获取id
System.out.println(user.getId());
}
截图如下:
然后,我们来看一下运行结果:
这里我们可以看到2个值,一个是code的值,为1,也是方法的返回值;第二个是插入数据的id,为32,是通过get方法得到的。
5.根据id进行删除
一样,我们先写UserDao.xml文件,代码如下:
<delete id="deleteById" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
截图如下:
其实出入参和上面的插入操作基本一致
下面来写接口,如图:
最后写测试文档,代码如下:
@Test
public void deleteById(){
int code = mapper.deleteById(32);
session.commit();
System.out.println(code);
}
截图如下:
然后,我们执行一下,看下运行结果:
这就没什么好说的了
6.修改数据
首先,我们来写UserDao.xml文件,代码如下:
<update id="update" parameterType="com.qcby.entity.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
where id= #{id}
</update>
截图如下:
然后,我们来写接口,截图如下:
然后,我们来写测试方法:
最后,我们来看一下结果:
一些理解:
我们能够发现,我们的插入与修改操作都是new了一个新对象,然后用新对象覆盖旧对象。插入就不多说什么了,这里说一下修改操作。我们在Navicat上执行修改操作时,感觉只是赋值就行,没什么特别的,而到这里,却要new新对象,我个人觉得这应该与实体类的包装有关。
7.小结
这里小结一下我们在增删改查中所用到的关键字
namespace:连接我们的对应的接口
id:唯一标识符,可以理解为方法名,要与接口中的方法名相同
resultType:返回值类型,确定时要根据sql语句考虑,而不是接口中的方法考虑
parameterType:可以理解为入参类型,即传给sql在值,也是根据sql来进行确定
selectKey:查询关键字,结合上面的例子进行分析
keyProperty:后面接关键字,与表有关
order:执行顺序,即在后面语句之前执行还是之后执行
#{}:这是用占位赋值的方式来拼接sql的,是Mybatis参数注入的一种方式。另外一种我们后面会讲并且会比较二者的不同。
到这里,我们的增删改查操作全部完成,当然,肯定不全,但是大体不差多少,后面的具体问题就具体分析了。
文中所写的一些个人理解如果有失偏颇,还请各位大佬指出!