一、增删改查
接下来我们通过映射文件的操作来实现mybatis对数据库的增删改操作
1.EmployeeMapper.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" >
<!-- namespace命名空间特殊作用: 如果使用mapper动态代理方法,这里就需要配置mapper接口地址-->
<mapper namespace="dao.EmployeeMapper">
<resultMap id="BaseResultMap" type="Bean.Student" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
</resultMap>
<!--插入方法-->
<insert id="addEmp" parameterType="Bean.Employee" >
insert into tbl_employee(last_name,email,gender)
values (#{lastName},#{email},#{gender})
</insert>
<!--更新方法-->
<update id="updateEmp" parameterType="Bean.Employee">
update tbl_employee
set last_name=#{lastName},email=#{email},gender=#{gender}
where id=#{id}
</update>
<!--删除方法-->
<delete id="deleteEmpById">
delete from tbl_employee where id=#{id}
</delete>
</mapper>
2.dao层接口
public interface EmployeeMapper {
public void addEmp (Employee employee);
public boolean updateEmp(Employee employee);
public void deleteEmpById(Integer id);
}
3.将映射文件注册到全局配置文件中:
<mappers>
<mapper resource="EmployeeMapper.xml"/>
</mappers>
4.测试类:
插入方法:
@Test
public void test03() throws IOException {
try {
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//插入
Employee employee = new Employee(null, "tom", "tom@qq.com", "0");
mapper.addEmp(employee);
System.out.println(employee.getId());
//手动提交
sqlSession.commit();
} catch (IOException e){
e.printStackTrace();
}
}
由于是获取主键自增,所以插入时将id置为null,mybatis会自动生成后去的id号。
运行结果:
修改方法:
@Test
public void test03() throws IOException {
try {
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//修改
Employee employee = new Employee(13, "jack", "jack@qq.com", "0");
boolean updateEmp = mapper.updateEmp(employee);
System.out.println(updateEmp);
//手动提交
sqlSession.commit();
} catch (IOException e){
e.printStackTrace();
}
}
运行结果:
删除方法:
@Test
public void test03() throws IOException {
try {
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//删除
mapper.deleteEmpById(13);
//手动提交
sqlSession.commit();
} catch (IOException e){
e.printStackTrace();
}
}
运行结果:
切记手动提交: sqlSession.commit();
二、注解式编程
1.编写dao层接口方法:
import Bean.Student;
import org.apache.ibatis.annotations.Select;
public interface StudentMapperAnnotation {
@Select("select * from student where id = #{id}")
Student getUserById(Integer id);
}
2.将dao层接口注册到全局配置文件中:
<mappers>
<mapper class="dao.StudentMapperAnnotation"/>
</mappers>
3.测试类:
@Test
public void test1() throws IOException {
try {
/**
* 通过Resource获取mybatis配置流
*/
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
/**
* 获取SqlSessionFactory实例
*/
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
/**
* 获取SqlSession实例
*/
SqlSession sqlSession = sqlSessionFactory.openSession();
/**
* 通过反射获取dao实例
*/
StudentMapperAnnotation mapper = sqlSession.getMapper(StudentMapperAnnotation.class);
Student student = mapper.getUserById(1);
//System.out.println(student.getClass());
System.out.println(student);
} catch (IOException e) {
e.printStackTrace();
}
}
运行结果:
三、获取主键自增
mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys
useGeneratedKeys = “true” :使用自增主键获取主键值
keyProperty :指定对应的主键属性,就是mybatis获取到主键值以后,将这个值分封装给javaBean的那个属性
<insert id="addEmp" parameterType="Bean.Employee" useGeneratedKeys="true" keyProperty="id">
insert into tbl_employee(last_name,email,gender)
values (#{lastName},#{email},#{gender})
</insert>
四、参数处理
1.多个参数处理:
单个参数:mybatis不会做特殊处理
#{参数名}:取出参数值多个参数:mybatis会做特殊处理
多个参数会被封装成一个map
key:param1…paramN,或者参数的索引也可以
value:传入的参数值
#{}就是从map中获取指定的key值;
出现的 异常:
org.apache.ibatis.binding.BindingException:
Parameter 'id' not found. Available parameters are [1, 0, param1, param2]
操作:
方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
取值:#{id},#{lastName}
命名参数:明确指定封装参数时map的key
POJO:
如果多个参数正好是我们业务逻辑的数据模型,可以直接传入pojo;
#{属性名}: 取出传入的pojo的属性值
Map:
多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,可以传入map
#{key}:取出map中对应的值
TO:
如果多个参数不是业务模型中的数据,但也经常使用,推荐来编写一个TO(Transfer Object)数据传输对象
Page{
int index;
int size;
}
思考:
public Employee getEmp(@Param(“id”)Integer id,String lastName);
取值:id==>#{id/param1} lastName==>#{param2}
public Employee getEmp(Integer id,@Param(“e”)Employee emp);
取值: id==>#{param1} lastName ==>#{param2.lastName/e.lastName}
###注意:如果是Collection(List,set)类型或是数组,
也会特殊处理,也是把传入的list或者数组封装在map中
public Employee getEmp(List ids);
取值:取出第一个id的值 : #{ids[0]}
测试:
dao层接口:
import Bean.Employee;
import org.apache.ibatis.annotations.Param;
public interface EmployeeMapper {
public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName") String lastName);
}
映射文件:
<select id="getEmpByIdAndLastName" resultType="Bean.Employee">
select * from tbl_employee where id =#{id} and last_name=#{lastName}
</select>
测试类:
@Test
public void test04() throws IOException {
try {
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpByIdAndLastName(1,"GINO");
System.out.println(employee);
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
2.源码 :myabtis如何处理参数
public Object getNamedParams(Object[] args) {
int paramCount = this.names.size();
//1.参数为null直接返回
if (args != null && paramCount != 0) {
//2.如果只有一个元素,并且没有Param注解;args[0] :单个参数直接返回
if (!this.hasParamAnnotation && paramCount == 1) {
return args[(Integer)this.names.firstKey()];
//3.多个元素或Param标注
} else {
Map<String, Object> param = new ParamMap();
int i = 0;
//4.遍历names集合 {0=id,1=lastName}
for(Iterator i$ = this.names.entrySet().iterator(); i$.hasNext(); ++i) {
Entry<Integer, String> entry = (Entry)i$.next();
//names集合的value作为key; names集合的key作为取值参考args[0]:args[1"Tom"]
//eg:{id:args[0]:1,lastName=args[1]:Tom}
param.put(entry.getValue(), args[(Integer)entry.getKey()]);
//add generic param names (param1,param2,…)
//额外的将每一个参数也保存到map中,是新的key:param1…paramN
String genericParamName = "param" + String.valueOf(i + 1);
if (!this.names.containsValue(genericParamName)) {
param.put(genericParamName, args[(Integer)entry.getKey()]);
}
}
return param;
}
} else {
return null;
}
}
总结:参数多的时候会封装map:为了不混乱,我们可以使用@Param来制定封装时使用的key
#{key}就可以取出,ap中的值;
(@Param(“id”)Integer id,@Param(“lastName”)String lastName);
ParamNameResolver解析参数封map过程:
//1.names:{0=id,1=lastName};构造器的时候就确定好了
1.获取每个标了param注解的参数的@Param的值:id lastName:赋值给name;
2.每次解析一个参数给map中保存信息:(key:参数索引,Value:name的值)
name的值:
标注了param注解:注解的值
没有标注:
1.全局配置:useActualParamName(jdk1.8):name=参数名
2.name=map.size():相当于当前元素的索引
{0=id, 1=lastName,2=2}
3.参数值得获取(#{}和${}的区别):
#{}:可以获取map中的值或者pojo对象属性的值
${}:可以获取map中的值或者pojo对象属性的值
区别:#{}:是以预编译的形式,将参数设置到sql语句中:PreparedStatement,防止sql注入
KaTeX parse error: Expected 'EOF', got '#' at position 46: … 大多情况下去参数值都应该使用#̲{} 原生jdbc不…{}进行取值
比如分表、排序:按照年份分表拆表
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
} else {
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}