沉迷于黑与白世界中的人,无论怎么挣扎,都逃不过被同化的命运。前世看见了什么,那么今世便是什么。
上一章简单介绍了MyBatis的简单了解(一),如果没有看过,请观看上一章。
一. Mybatis 的官方介绍
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索。MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。
现在都是用Mapper 的形式来进行数据库的持久化操作,但是以前的ibatis 形式的 命名空间方式的CRUD ,也需要进行了解。 下面,就进行详细的分析。
二. 查询语句 select
二.一 根据id 查询单个对象
接口:
User getById(int userId);
实现类:
@Override
public User getById(int userId) {
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
User user=null;
try{
user=sqlSession.selectOne("com.yjl.pojo.User.getById",userId);
}finally{
sqlSession.close();
}
return user;
}
对应的xml 查询语句:
<select id="getById" parameterType="int" resultType="com.yjl.pojo.User">
select * from user where id=#{id}
</select>
测试方法:
@Test
public void getByIdTest(){
UserDao userDao=new UserDaoImpl();
User user=userDao.getById(1);
System.out.println(user);
}
查询对象的时候,如果可以确定 查询的是唯一的对象(包括没有,没有查询出来为null),那么就可以使用selectOne() 来精确的表示出唯一的对象。 后面跟的值, 是名称空间+id的形式, 命名空间来确定是哪一个实体, com.yjl.pojo.User 表示 是User 实体类, getById 表示确定的是getById() 的方法。 其中, id不能重复。
对User.xml 的解释。
namespace 为命名空间,一般是用包名+类名 即全限定名称。 sql 语句的id 一般是方法名,是唯一的,不能重复。 (接口中的方法名可以重载,可以重复,但是id是不能重复的,但一般还是用方法名来写id)。
是查询语句,用的是select parameterType 为参数类型, 是int 型, int 是MyBatis 内置的对象类型, 与Java 中的java.lang.Integer 一致。 Java 类型,MyBatis 类型,数据库类型 ,这三种类型有一种转换的关系。 以后会讲。
resultType 为结果类型, 自定义的类型,要写 全限定名称,如com.yjl.pojo.User, 以后也可以写别名。
其中,#{id} 表示传入的参数 放置到id 里面。 会采用 占位符的方式,转换成
select * from user where id=?, ?传入的参数值为id参数值。
如果传入的值是单个的基本类型值的话,可以用value 来代替。
只能是单个的值,并且是基本类型值。
<select id="getById" parameterType="int" resultType="com.yjl.pojo.User">
select * from user where id=#{value}
</select>
如果传入两个值,如 :
<select id="getById" parameterType="int" resultType="com.yjl.pojo.User">
select * from user where id=#{value} and name=#{name}
</select>
这样是错误的。
二.二 查询全部的记录
接口:
List<User> findAll();
实现类:
@Override
public List<User> findAll() {
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
List<User> allList=new ArrayList<User>();
try{
allList=sqlSession.selectList("com.yjl.pojo.User.findAll");
}finally{
sqlSession.close();
}
return allList;
}
对应的xml sql语句
<select id="findAll" resultType="com.yjl.pojo.User">
select * from user
</select>
测试方法:
@Test
public void findAllTest(){
UserDao userDao=new UserDaoImpl();
List<User> allList=userDao.findAll();
allList.forEach(n ->System.out.println(n));
}
没有传入参数值,那么就不写 参数值, 虽然查询的是一个集合list, 但是返回类型resultType 仍然写 类的全限定名称, MyBatis 会根据调用方法的名称 selectList() 来自动内部构建集合。
注意点:
- 在查询的时候,如果查询的是单个对象的话,也是可以用selectList() 的,只是此时查询出来是一个长度的集合。 但是,如果查询的是多个对象的话,是不能用selectOne() 的,会报错。
@Override
public List<User> findAll() {
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
List<User> allList=new ArrayList<User>();
User user=sqlSession.selectOne("com.yjl.pojo.User.findAll");
allList.add(user);
return allList;
}
TooManyResultsException, 太多结果记录异常。
- 在查询的时候,除了selectOne(), selectList() 之外,还有其他的查询结果 ,如Map 形式。
以后,会讲其余的用法。
三. 插入语句 insert
三.一 普通插入
接口:
int insert(User user);
实现类 (错误的形式):
@Override
public int insert(User user) {
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
int result= sqlSession.insert("com.yjl.pojo.User.insertUser", user);
sqlSession.close();
return result;
}
测试方法:
@Test
public void insertTest(){
UserDao userDao=new UserDaoImpl();
User user=new User();
user.setName("老蝴蝶");
user.setAge(25);
user.setSex("男");
user.setDescription("这是一个老蝴蝶");
userDao.insert(user);
System.out.println("输出信息:"+user);
}
xml实现类:
<insert id="insertUser" parameterType="com.yjl.pojo.User">
insert into user(name,age,sex,description) values(#{name},#{age},#{sex}
,#{description})
</insert>
传入的参数是 com.yjl.pojo.User 对象, #{name} 表示从对象参数中取出name 的值, #{sex} 表示从对象参数中取出sex的值。
在日志中,执行了插入的语句,但是并没有在数据库中找到这一条记录。
原因是什么, 就是自动提交的问题。 上面把自动提交 改成了false, 那么就需要我们手动提交。
所以,正确的实现方法是:
@Override
public int insert(User user) {
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
int result= sqlSession.insert("com.yjl.pojo.User.insertUser", user);
sqlSession.commit(); //手动提交
sqlSession.close();
return result;
}
下面的更新和删除,都要进行手动提交。
这个时候,运行程序:
而数据库中也存在了这一条数据
插入的编号是4, 3的那一条已经被使用了,刚才错误插入的时候。
三.二 插入时获取id
从输出结果中,发现,数据可以插入到数据库中,但是并没有 查询出相应的id 编号。
应该要将id 编号进行取出。 实际开发中,表关联时,常常获取刚才插入表的 id 主键,来进行 关联表的外键关联值。
<!-- 插入记录 ,获取id编号-->
<insert id="insertUser" parameterType="com.yjl.pojo.User" keyProperty="id" useGeneratedKeys="true">
insert into user(name,age,sex,description) values(#{name},#{age},#{sex}
,#{description})
</insert>
其中,useGeneratedKeys= true, 表示用主键信息, keyProperty 指定主键 为类属性 为id, 注意,用keyProperty ,不能用keyColumn
此时,运行:
数据库中也存在这条记录, id为5
三.三 数据库查询 id
<!-- 数据库查询,获取id编号-->
<insert id="insertUser" parameterType="com.yjl.pojo.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id()
</selectKey>
insert into user(name,age,sex,description) values(#{name},#{age},#{sex}
,#{description})
</insert>
顺序 order, 为AFTER, 在插入之后查询。 必须为全大写 AFTER, after 是错误的。
返回类型 resultType, 表示是 主键的类型,为全限定名称, java.lang.Integer,
last_insert_id () 是MySQL 数据库提供的内置查询 方法,自动返回最后一个INSERT或 UPDATE 问询为 AUTO_INCREMENT列设置的第一个 发生的值。
三.四 uuid 形式的主键插入
将id 的类型 改成String 类型,
数据库中id 列的类型也改成varchar 类型。
长度要设置长一点。
将User.xml 中的其他方法 注释掉。
写测试方法:
@Test
public void insertUUIDTest(){
UserDao userDao=new UserDaoImpl();
User user=new User();
user.setName("老蝴蝶uuid");
user.setAge(25);
user.setSex("男");
user.setDescription("这是一个老蝴蝶uuid 测试");
userDao.insert(user);
System.out.println("输出信息:"+user);
}
xml sql 语句。
<!-- uuid插入,获取id编号-->
<insert id="insertUser" parameterType="com.yjl.pojo.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>
<!-- 这个时候,sql 语句就要写id 了。 -->
insert into user(id,name,age,sex,description) values(#{id},#{name},#{age},#{sex}
,#{description})
</insert>
其中, 查询时顺序 order 就为BEFORE, 在插入之前进行查询, 不能写before ,必须为大写
uuid 的类型是String
select uuid() ,其中 uuid() 为mysl 提供的内置函数 。
插入的sql 语句,就需要写 id 的值了。
数据库中展示:
三.六 序列形式的插入
id 编号 还改成int 类型, 是自动增长, 数据库列id 还改成int 类型 ,自增。注释的sql 解除注释。
跟uuid 之前的操作一样。
没有oracle 客户端,不进行验证了。
<!-- oracle 序列插入,获取id编号-->
<insert id="insertUser" parameterType="com.yjl.pojo.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Integer">
select 序列名.nextval()
</selectKey>
<!-- 这个时候,sql 语句就要写id 了。 -->
insert into user(id,name,age,sex,description) values(#{id},#{name},#{age},#{sex}
,#{description})
</insert>
四.修改 update
四.一 全部修改时
接口:
int update(User user);
实现方法:
@Override
public int update(User user) {
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
int result= sqlSession.update("com.yjl.pojo.User.updateUser",user);
sqlSession.commit(); //手动提交
sqlSession.close();
return result;
}
测试方法:
@Test
public void updateTest(){
UserDao userDao=new UserDaoImpl();
User user=new User();
user.setId(1); //编号为1
user.setName("修改老蝴蝶");
user.setAge(25);
user.setSex("男");
user.setDescription("这是一个修改的老蝴蝶");
userDao.update(user);
}
xml 修改语句
<update id="updateUser" parameterType="com.yjl.pojo.User">
update user set name=#{name},sex=#{sex},age=#{age},description=#{description}
where id=#{id}
</update>
运行时:
数据库:
确实发生了修改的操作。是正确的。
四.二 部分修改字段时
xml 不变。
测试方法:
@Test
public void update1Test(){
UserDao userDao=new UserDaoImpl();
User user=new User();
user.setId(1);
user.setDescription("这是一个老蝴蝶,只修改描述");
userDao.update(user);
}
传入的值为空,
这样修改的话,#{name} 时取出的值 是默认的String 为null, #{age} 也是默认的Integer, 为null. 表示修改的传入值是null .
四.三 查询时修改
将id =1 的值设置成原先的值
xml 不变,测试方法为:
@Test
public void update2Test(){
UserDao userDao=new UserDaoImpl();
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
User user=sqlSession.selectOne("com.yjl.pojo.User.getById",1);
user.setDescription("这是一个老蝴蝶,只修改描述");
userDao.update(user);
}
可以正确的进行修改。
如果一个表中 有几十个字段,而现在只修改 一个描述字段,会将以前所有的字段都进行修改, 很浪费资源的。 希望 可以修改哪一个,就只修改哪一个, 后面的动态sql 语句会学习的。
五. 删除 delete
接口:
int delete(int id);
实现类:
@Override
public int delete(int id) {
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
int result= sqlSession.delete("com.yjl.pojo.User.deleteById",id);
sqlSession.commit(); //手动提交
sqlSession.close();
return result;
}
测试方法:
@Test
public void deleteTest(){
UserDao userDao=new UserDaoImpl();
userDao.delete(1);
}
xml 语句:
<!-- 删除记录 -->
<delete id="deleteById" parameterType="int">
delete from user where id=#{id}
</delete>
写正常的删除语句。
运行:
六. 注意点
这就是原来 ibatis 时的命名空间的 单表基本操作, 当然 ,也有其他的操作形式,这里暂不讲解,会在Mapper 时进行详细的讲解。
另外注意, sql 语句时, 如:
delete from user where id=#{id}
加上; 和不加; 都可以运行, 但不建议加; 号。
谢谢!!!