一. 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() 来自动内部构建集合。
注意点:
1.在查询的时候,如果查询的是单个对象的话,也是可以用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>