Spring Boot专栏六:JDBC的简单使用
本节专栏我们来介绍JDBC的简单使用
什么是JDBC
如果想完整充分学习JDBC,可以参考大佬们的博客,比如:学JDBC,这一篇就够了
我在这里拾人牙慧,冒昧地援引一下:
JDBC 规范定义接口,具体的实现由各大数据库厂商来实现。
JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个
数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用 JDBC 接口中的方法即可,数据库驱动由数据库厂商提供。
使用 JDBC 的好处:
简单来说,JDBC的全称是Java Database connectivity,也就是Java访问、使用数据库的一个接口(连接的口,不是interface那个接口),我们只需要按照sql语言的规则写出来,数据库,比如MysqL,就会自动替我们去执行操作。
xxxDao.xml的内容怎么写
专栏第四节粗略地讲了xml文件的内容怎么写,本节具体地来介绍一下。
xml头部的内容
在专栏第四节中,我们提到了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" >
这个是固定死的,除非xml或者mybatis等的版本变化了,否则我们就是这么写。以后我们写其他的xxxDao.xml文件,只要复制这段话就行了。
mapper对的内容
在专栏第四节中,xml文件的主要内容包括在一个mapper对<mapper> </mapper>中:
<mapper namespace="com.example.demo.dao.UserDao">
<select id="show_user_all" resultType="com.example.demo.entity.User">
select *
from user__
</select>
<select id="show_user_by_user_name" parameterType="String" resultType="com.example.demo.entity.User">
select user_name, user_password, register_time, login_time
from user__
where user_name=#{user_name}
</select>
</mapper>
其中,mapper对有个参数namespace,它代表该xml文件对应哪个Dao.java文件吗。第四节中也提到了,这句话是找到对应Dao的关键。
其他的两个select对,就是和JDBC有关了,我们看下一节
使用JDBC手写sql语句
本小节的内容基于大家有基本的sql语句基础。在Spring Boot中,一般把JDBC语言写到xml文件中,方便日后维护。下面我们来讲解如何写sql语句,这里我们只讲增删查改四类语句,不涉及add, alert, drop等语句。
增insert
增 insert,首先我们要在xml的语句对的开头写<insert …>,在对结束的时候写</insert>.
在<insert …>中,有这么几个重要的参数:
- id:这个参数不止是insert有,其他的删改查也都有,是用来对应Dao.java文件中的方法名称——所以这部分一定要注意,如果对不上,就会报错;
- useGeneratedKeys:是否自动生成主键。这个地方挺坑的,我研究了挺久。
先说一下这个参数怎么用:当它的值为"true"时,数据库默认将数据表中的第一列、第一个属性当作主键,进行自增;如果不想默认的话,可以通过修改keyProperty和keyColumn这两个参数,来指定主键。
但是自动生成主键,只对MysqL等几种数据库适用,大部分还是不适用的。另外,自动设置主键,需要我们在MysqL中关闭“自动生成主键”(通过navicat可以设置)——听起来就很晕乎,所以我建议,大家把useGeneratedKeys设置为"false",keyProperty和keyColumn这两个参数都不用,并且在增加数据的时候,把主键也当作要插入的一个值,加进去。
有同学会问了,新增一个用户,怎么能知道这个用户的id?这就需要我们先去查找当前最大的user_id,记为max_id,然后令新用户的id为max_id+1即可(这个sql语句我放到查询语句的写法中讲)。或者如果大家已经在navicat中对user_id设置了“自动递增”,那么就可以不用管user_id这个属性了,navicat软件自动帮我们递增了。
接下来我们看一下一个实例,如何在用户表中插入一个新的用户,在给定user_id(通过上述方法取得), user_name, user_phone, user_password, user_wallet, register_time, login_time的情况下:
<insert id="add_user" useGeneratedKeys="false">
insert into
user_ (user_id, user_name, user_phone, user_password, user_wallet, register_time, login_time)
values (#{user_id}, #{user_name}, #{user_phone}, #{user_password}, #{user_wallet}, #{register_time}, #{login_time})
</insert>
此时在UserDao.java接口中,应该有一个如下的方法,与上述xml语句对应:
int add_user(@Param("user_id") int user_id, @Param("user_name") String user_name,
@Param("user_phone") String user_phone, @Param("user_password") String user_password,
@Param("user_wallet") double user_wallet, @Param("register_time") String register_time,
@Param("login_time") String login_time);
UserService.java和UserServiceImple.java中应该也有对应的代码,留给大家当作作业,我会上传代码到github上去,大家可以参考。
最后,注意一下insert语句的返回值,是int型的,它表示向数据库中成功插入了多少条记录;若插入失败,返回0。
删delete
删delete,首先我们要在xml的语句对的开头写<delete…>,在对结束的时候写</delete>.
在<delete…>中,有这么几个重要的参数:
- id:同insert中的介绍;
- parameterType:对于删改查三种操作,如果Dao.java中的方法中有且只一个输入,那么可以添加一个参数parameterType,用来表示该输入的类型。我们一会用基本数据类型和字符串做个演示,复杂的类型一会再作说明。
接下来我们用两个实例来说明,第一个是根据user_id来删除用户,第二个是根据user_name来删除:
<delete id="delete_user_by_user_id" parameterType="int">
delete from
user_
where user_id=#{user_id}
</delete>
<delete id="delete_user_by_user_name" parameterType="String">
delete from
user_
where user_name=#{user_name}
</delete>
对应UserDao.java接口中的两个方法:
int delete_user_by_user_id(@Param("user_id") int user_id);
int delete_user_by_user_name(@Param("user_name") String user_name);
delete语句的返回值,也是int型的,它表示向数据库中成功删除了多少条记录;若一条都没有删除,返回0。
改 update
改 update,首先我们要在xml的语句对的开头写<update…>,在对结束的时候写</update>.
在<update…>中的参数同<delete …>。但一般用不到parameterType,原因也好理解:update语句中需要set 某某等于某某,且where 某某等于某某,也就是说一般会有两个参数,所以parameterType用到得不多。
接下来我们用两个实例来说明,第一个是修改用户名,第二个是进行充值,二者都是基于user_id进行修改的:
<update id="update_user_name_by_user_id">
update
user_
set user_name=#{user_name}
where user_id=#{user_id}
</update>
<update id="update_user_wallet_by_user_id">
update
user_
set user_wallet=#{user_wallet}
where user_id=#{user_id}
</update>
对应UserDao.java接口中的两个方法:
int update_user_name_by_user_id(@Param("user_id") int user_id, @Param("user_name") String user_name);
int update_user_wallet_by_user_id(@Param("user_id") int user_id, @Param("user_wallet") double user_wallet);
这里有同学可能会有疑问,第二个方法不是说好了是要充值吗,那不就是要在原余额数上加一个数吗,怎么变成了赋值?我是这么考虑的,因为还有支付这个功能,这二者都是对user_wallet进行操作。如果我把它写成一个方法,同时在controller层写方法时,提前计算好充值或支付后的余额,进行修改操作,这样节省了代码量。如果有朋友认为这两个功能应该分开来写,也是有道理的,功能原子化嘛,各有各的道理,这就看写项目时,项目经理怎么考虑了。
update语句的返回值,也是int型的,它表示向数据库中成功更改了多少条记录;若一条都没有更改,返回0。
查 select
查 select,首先我们要在xml的语句对的开头写<select…>,在对结束的时候写</select>.
在<select…>中的参数有三个:
- id:同delete中的介绍
- parameterType:同delete中的介绍
- resultType:这个是select独有的一个参数,代表返回值的类型(其他三类的返回值都为int),这个是一个必选项,因为无论你想让数据库返回的是一个属性还是多个属性,都可以用java中的基本数据类型或包装类或一个自定义的类来记录下来,肯定能对应上一个返回值类型
接下来我们演示的几个案例,都是返回值为简单数据类型,复杂的返回值类型,我放到下面几个小节来讲。
接下来我们用两个实例来说明,第一个是查询当前最大的用户id,第二个是查询某个用户的钱包余额(根据用户id):
<select id="select_max_user_id" resultType="int">
select max(user_id)
from user_
</select>
<select id="select_user_wallet_by_user_id" parameterType="int" resultType="double">
select user_wallet
from user_
where user_id=#{user_id}
</select>
对应UserDao.java接口中的两个方法:
int select_max_user_id();
double select_user_wallet_by_user_id(@Param("user_id") int usre_id);
返回值为一个类/对象
显然,这种情况只会在select语句中出现。除非是java.lang中的类,否则我们要写清楚该类的具体位置。我们之前就遇到过这种例子,根据用户id查询用户的一些信息:
<select id="show_user_by_user_name" parameterType="String" resultType="com.example.demo.entity.User">
select user_name, user_password, register_time, login_time
from user_
where user_name=#{user_name}
</select>
可以看到我们在resultType中写的是"com.example.demo.entity.User"。注意,在这种情况下,要在类中添加对应的构造方法。
输入为一个类/对象
这种情况可以在任何一种sql语句中出现,由于此时的输入往往只有一个,因此一般需要添加parameterType参数(insert语句除外),写的方法和上述“返回值为一个类/对象”相同。
下面介绍一个根据用户名修改用户密码的sql语句,其中输入为一个User类:
<update id="update_user_name_by_user_id_Class" parameterType="com.example.demo.entity.User">
update
user_
set user_password=#{user.user_password}
where user_name=#{user.user_name}
</update>
注意这种情况下sq语句的写法,尤其是user_password=#{user.user_password}和user_name=#{user.user_name}
对应UserDao.java接口中的方法:
int update_user_name_by_user_id_Class(@Param("user") User user);
返回值为一个列表、数组
首先,我建议大家将所有的数组转化为列表,这样方便进行操作,因为在java中列表毕竟是一个类,而数组不是。
然后,当返回值是一个列表时,我们不必刻意做改变。我们之前就遇到过这种例子,查询所有用户的所有信息:
<select id="show_user_all" resultType="com.example.demo.entity.User">
select *
from user_
</select>
resultType仍然是类,JDBC如果收到多个输出,就会自动帮我们包装成列表。
输入为一个列表、数组
这里依然建议大家用列表。
输入如果仅有列表时,那么就需要用到parameterType参数,且参数值填为:java.util.List
另外,在sql语句中使用列表时,也需要做更改,下面我们举一个根据用户id数组查询用户名的用例:
<select id="select_user_name_list_by_user_id_list" parameterType="java.util.List" resultType="String">
select user_name
from user_
where
<foreach collection="user_id_list" item="item" index="index" separator="or">
user_id=#{item}
</foreach>
</select>
注意在where子句中加了一个<foreach …></foreach>对,其中的colleaction参数对应Dao类方法中@Param参数,item与index就按照我这里写的就行,separator参数的值表示用什么字符串来分割<foreach …></foreach>对中的内容,在where子句中当然是用or来分割,因为我们要写成user_id=1 or user_id=2这样的。如果是update中的set子句,那么要用,来分割……这部分大家自己理解。
在user_id=#{item}中要写item,表示那个元素是遍历了列表的每个元素
对应UserDao.java接口中的方法:
List<String> select_user_name_list_by_user_id_list(@Param("user_id_list") List<Integer> user_id_list);
返回值选择基本属性还是包装类
返回值可以是int, double等基本数据结构,也可以是Integer, Double等包装类。在使用JDBC中,正常情况下它们的返回值是一样的;但是,如果搜索到的结果为空,那么
- 如果返回值为基本数据结构,则返回该基本数据结构的初始化值,比如int返回0,double返回0.0;
- 如果返回值为包装类,则返回null;
注意小于号<和大于号>
最后要注意的是,在xml语句中,不能用<表示小于,不能用>表示大于,因为它默认这两个符号表示<select>等中的“对”。
所以如果我们要在sql语句中比较大小,要将<表示成"<",>表示成">",其意义分别为less than和greater than.
要表示小于等于、大于等于、不等于也很简单,分别是:"<=", “>=”, “<>”
本节专栏的内容到此结束,为了方便大家拷贝代码,我已经将我的项目放到了github上,项目地址为https://github.com/DTSSDUTDeepLearning/Spring-Boot-Dante,有需求的朋友们自行前往,目前网站还不完善,请大家包涵,后期我会抓紧时间完善。
谢谢大家的阅读。