3.7添加用户
3.7.1映射文件
在User.xml中配置添加用户的Statement
<!-- 添加用户
parameterType:指定输入参数类型是pojo(包括用户信息)
#{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值
-->
<select id="insertUser" parameterType="cn.itcast.po.User">
insert into users(username,password) values(#{username},#{password})
</select>
3.7.2程序代码
//添加用户信息
@Test
public void InsertUserTest() throws IOException {
//mybaits配置文件
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
//创建回话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession操作数据库
SqlSession sqlSession=sqlSessionFactory.openSession();
//通过SqlSession操作数据库
//第一个参数:映射文件中的statement的id,等于namespace+.+statement的id
//第二个参数:指定和映射文件中所匹配的parameterType类型的参数
//插入用户对象
User user=new User();
user.setUsername("赵信");
user.setPassword("打野");
sqlSession.insert("test.insertUser", user);
//提交事务
sqlSession.commit();
//关闭会话
sqlSession.close();
}
3.7.3自增主键返回
mysql自增主键,执行insert提交之前自动生成一个自增主键
通过mysql函数获取到刚提交记录的自增主键
LAST_INSERT_ID()
是在insert之后调用
3.7.4 非自增主键的返回(使用uuid)
使用mysql的uuid()函数生成主键,需要修改表中字段类型改为string,长度设置35位,
执行思路:
先通过uuid()语句得到主键,
执行uuid()语句顺序相当于insert语句之前执行。
<!-- 使用mysql的uuid()生成主键
执行过程:
首先通过uuid()得到主键,将主键设置到user对象的id属性,
其次再insert执行时,将user对象中取出uuid的值
uid是User对象的属性,类型必须要和resultType的值对应
-->
<!-- <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>
insert into users(uid,username,password) values(#{uid},#{username},#{password})-->
3.8删除用户
3.8.1删除用户映射文件
<!-- 删除用户
根据id删除用户,需要传入id
-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from users where uid=#{id}
</delete>
3.8.2删除用户代码
//删除用户信息
@Test
public void DeleteUserTest() throws IOException {
//mybaits配置文件
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
//创建回话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession操作数据库
SqlSession sqlSession=sqlSessionFactory.openSession();
//通过SqlSession操作数据库
//第一个参数:映射文件中的statement的id,等于namespace+.+statement的id
//第二个参数:传入id,删除用户
sqlSession.delete("test.deleteUser",7);
//提交事务
sqlSession.commit();
//关闭会话
sqlSession.close();
}
3.9 更新用户
3.9.1 更新用户映射文件
<!-- 根据id更新用户
分析:需要传入用户的id
需要传入用户的更新消息
parameterType指定user对象,包括id和更新信息,注意,id必须存在
#{id}从输入的对象中获取id的属性值,
-->
<update id="updateUser" parameterType="cn.itcast.po.User">
update users set username=#{username},password=#{password} where uid=#{uid}
</update>
3.9.2更新用户代码
//更新用户信息
@Test
public void UpdateUserTest() throws IOException {
//mybaits配置文件
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
//创建回话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession操作数据库
SqlSession sqlSession=sqlSessionFactory.openSession();
//通过SqlSession操作数据库
//第一个参数:映射文件中的statement的id,等于namespace+.+statement的id
//第二个参数:指定和映射文件中所匹配的parameterType类型的参数
//插入用户对象
User user=new User();
//必须设置id
user.setUid(5);
user.setUsername("大龙");
user.setPassword("打打打");
sqlSession.insert("test.updateUser", user);
//提交事务
sqlSession.commit();
//关闭会话
sqlSession.close();
}
3.10总结
3.10.1 parameterType
在映射文件中通过parameterType指定输入参数的类型
3.10.2 resultType
在映射文件中通过resultType指定输出结果类型
3.10.3 #{}和${}
#{}表示一个占位符,#{}接收输入参数,可以是简单类型,pojo,hashmap
如果接收简单类型,#{}中可以写成value或其他名称。#{}接收pojo对象值,通过ognl读取对象中的属性值。通过属性.属性.属性....的方式获取。
${}表示一个拼接符号,会引起sql注入,所以不建议使用。
${}接收输入参数,类型可以是简单类型,pojo,hashmap
如果接收简单类型,${}中只能写成value或者其他名称。
3.10.4 selectOne 和selectList
selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现,使用selectList也可以实现
selectList表示查询出一个列表(多条记录)进行映射。selectOne不能够代替。
3.11 mybatis和hibernate本质区别和应用场景
hibernate: 是一个标准的ORM框架(对象关系映射),入门门槛较高的,不需要程序员写sql,sql语句自动生成了。
对sql语句进行优化,修改比较困难。
应用场景:
适用于需求变化不多的中小型项目,比如后台管理系统,erp、orm、o。。。
mybatis:专注的是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全的ORM框架。虽然程序员自己写sql,mybatis也可以实现映射(输入输出)。
应用场景:
适用于需求变化较多的项目,比如:互联网项目。
企业进行技术选型,以低成本,噶火爆作为技术选型原则,根据项目组的技术选型。
4 mybatis开发dao的方法
4.1 SqlSession使用范围
4.1.1 SqlSessionFactoryBuilder
通过SqlSessionFactoryBuilder创建回话工厂sqlSessionFactory
将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理,SqlSessionFactoryBuilder
在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。
4.1.2 SqlSessionFactory
通过SqlSessionFactory创建SqlSession,适用单例模式管理sqlSessionFactory(工厂一旦创建,适用一个实例)
将来mybatis和spring整合后,适用单例模式管理sqlSessionFactory
4.1.3 SqlSession
SqlSession是一个面向用户(程序员)的接口
SqlSession中提供了很多操作数据库的方法:如selectOne(返回单个对象)、selectLisst(返回单个)
SqlSession是线程不安全的,在SqlSession实现类中,除了有接口中操作数据库的方法,还有数据域属性,
SqlSession最佳应用场合在方法体内,定义成局部变量使用。
4.2 原始dao开发方法(程序员需要些dao接口和dao实现类)
4.2.1 思路
程序员需要些dao接口和dao实现类
需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession
4.2.2 测试代码
定义接口。
package cn.itcast.mybatis.dao;
import cn.itcast.po.User;
public interface UserDao {
//根据id查询用户信息
public User findUserById(int id)throws Exception;
//添加用户信息
public void insertUser(User user)throws Exception;
//删除用户信息
public void deleteUser(int id)throws Exception;
}
实现接口。
package cn.itcast.mybatis.dao;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import cn.itcast.po.User;
public class UserDaoImpl implements UserDao{
//需要向dao实现类中注入SqlSessionFactory
//这里通过构造方法注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory=sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", id);
//释放资源
sqlSession.close();
return user;
}
@Override
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
@Override
public void deleteUser(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", id);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
}
通过测试类进行测试。
package cn.itcast.mybatis.test;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.dao.UserDao;
import cn.itcast.mybatis.dao.UserDaoImpl;
import cn.itcast.po.User;
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
//此方法是在执行testFindUserById之前执行
@Before
public void setUp()throws Exception{
//创建sqlSessionFactory
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
//创建回话工厂,传入mybatis的配置文件信息
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
//创建UserDao的对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
User user=userDao.findUserById(1);
System.out.println(user);
}
}
4.2.3 原始dao开发方法问题
1 ,dao接口实现类中存在大量模板方法,摄像能否将这些代码提取出来,打打减轻程序员的工作量,。
2 ,调用sqlsession方法时将statement的id硬编码了。
3 ,调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,也不报错。
4.3 mapper代理方法(程序员只需要mapper接口,相当于dao接口)
4.3.1 思路(mapper开发规范)
程序员还需要编写mapper.xml映射文件
程序员只要编写mapper接口需要遵循一些开发规范,mabatis可以自动将生成mapper接口实现类代理对象。
开发规范:
1 ,在mapper.xml中,namespace等于mapper接口地址。
<!-- namespace命名空间,作用就是对sql进行分了化管理,理解sql隔离
注意:使用mapper代理方法,namespace有特殊作用 -->
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
2 ,mapper.java接口中的方法名和mapper.xml中statement的id一致。
3 ,mapper.java接口中的方法输入参数类型 和mapper.xml中的statement的parameterType指定的类型一致。
4 ,mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。
<select id="findUserById" parameterType="int" resultType="cn.itcast.po.User">
select * from users where uid=#{id}
</select>
配置文件将与接口中定义的方法一一对应,id对应着接口名,parameterType代表传入参数类型,resultType代表返回类型
//UserMapper.java接口 根据id查询用户信息
public User findUserById(int id)throws Exception;
总结:
以上开发规范主要对下面代码统一生成,
User user=sqlSession.selectOne("test.findUserById", 1);以及
List<User> list=sqlSession.selectList("test.findUserByName","sa");等
4.3.2 mapper.java
public interface UserMapper {
//根据id查询用户信息
public User findUserById(int id)throws Exception;
4.3.3 mapper.xml
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="cn.itcast.po.User">
select * from users where uid=#{id}
</select>
4.3.4 在SqlMapConfig.xml中加载mapper.xml
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
4.3.5 测试
package cn.itcast.mybatis.test;
import static org.junit.Assert.*;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.mapper.UserMapper;
import cn.itcast.po.User;
public class UserMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
//创建sqlSessionFactory
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
//创建回话工厂,传入mybatis的配置文件信息
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
//创建UserMapper对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);//重点
//调用UserMapper的方法
User user=userMapper.findUserById(2);
System.out.println(user);
}
}
4.3.6一些问题的总结
4.3.6。1代理对象内部调用selectOne或者selectList
如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库,
如果mapper方法返回集合对象selectList查询数据库,如果用selectOne,则会导致报错。
4.3.6.2 mapper接口方法参数只能有一个,是否影响系统开发
mapper接口方法参数只能有一个,系统是否不利于系统维护
系统框架中,dao层的代码是被业务层公用的,即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。
注意:持久层方法的参数可以用包装类型,map.....,service方法中建议不要使用包装类型(不利于业务层的可扩展性)。