Mybatis基本使用
1.日志输出
在mybatis-config.xml 中的settings 标签配置 mybatis的设置项
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
设置日志的属性是 logImpl,其候选值有 SLF4J、LOG4J、LOG4J2、STDOUT_LOGGING、NOLOGGING等
2. #{} 和 ${} 区别
#{} :表示占位符 + 赋值,也就是先用 ? 去占位,然后把你传进来的值赋值进去。
<select id="queryById" resultType="com.ztone.pojo.Employee">
select emp_id empId, emp_name empName, emp_salary empSalary from t_emp
where emp_id = #{id};
</select>
可以看到sql的执行是先用 ? 进行占位,然后把参数赋值进去
${}:表示字符串拼接,是直接把你传进去的值拼接到sql语句上
<select id="queryById" resultType="com.ztone.pojo.Employee">
select emp_id empId, emp_name empName, emp_salary empSalary from t_emp
where emp_id = ${id};
</select>
可以看到,这种方式是直接把参数拼接到了 sql 中
建议使用#{} ,可以防止注入问题,但是这种方式只能是将sql语句中的值去占位,不能将列名占位,如果想动态控制列名就要使用 ${}
3. 传入参数
在使用 #{} 或 ${} 接值的时候传入参数的规定
3.1 单个参数
简单类型如 Integer、Float、Double等,在 #{} 中可以随意起名,但建议和传入的参数名相同,如上面的id
如果参数是实体对象,在接收值的时候就是用 该对象的属性
public interface EmployeeMapper {
int insertEmp(Employee employee);
}
<insert id="insertEmp">
insert into t_emp(emp_name, emp_salary) values(#{empName}, #{empSalary});
</insert>
3.2 多个参数
简单类型
当你传入的参数是多个时,就不能随意起名了,也不能用 传入的参数名。
public interface EmployeeMapper {
List<Employee> queryByNameAndSalary(String name, Double salary);
}
有三种解决方案:
-
在这个方法的形参上使用@Param注解来指定参数的名称,在sql语句中就可以使用这个名称了
public interface EmployeeMapper { List<Employee> queryByNameAndSalary(@Param("empName") String name, @Param("empSalary") Double salary); }
<select id="queryByNameAndSalary" resultType="com.ztone.pojo.Employee"> select emp_id empId, emp_name empName, emp_salary empSalary from t_emp where emp_name = #{empName} and emp_salary = #{empSalary} </select>
-
mybatis 的特殊机制,是根据参数的索引,arg0、arg1 .......
<select id="queryByNameAndSalary" resultType="com.ztone.pojo.Employee"> select emp_id empId, emp_name empName, emp_salary empSalary from t_emp where emp_name = #{arg0} and emp_salary = #{arg1} </select>
-
第三种方式和第二种类似。param1、param2.......
Map类型,使用map的key接收值
public interface EmployeeMapper {
int insertEmpMap(Map employeeMap);
}
<insert id="insertEmpMap">
insert into t_emp(emp_name, emp_salary) values(#{name}, #{salary});
</insert>
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Map map = new HashMap();
map.put("name","zhangsan");
map.put("salary",200.0);
int i = mapper.insertEmpMap(map);
4.返回值指定
4.1 返回单个
在DML(插入、删除、更新)操作中不需要指定返回值的类型,都是int
在查询操作中,如果返回的是基本数据类型
在<select 标签中的resultType属性指定 返回值的类型,一般是类的全限定符
public interface EmployeeMapper {
String queryNameById(Integer id);
Double querySalaryById(Integer id);
}
<select id="queryNameById" resultType="java.lang.String">
select emp_name empName from t_emp where emp_id = ${id};
</select>
<select id="querySalaryById" resultType="java.lang.Double">
select emp_salary empName from t_emp where emp_id = ${id};
</select>
Mybatis 提供了 常用类型的 简单别名,基本数据类型 int --> _int double--> _double
包装数据类型 Double 可以直接使用double
String 的别名是 string
map、list 也是如此
如果返回值类型是对象,也需要写出全限定符
<select id="queryByNameAndSalary" resultType="com.ztone.pojo.Employee">
select emp_id empId, emp_name empName, emp_salary empSalary from t_emp
where emp_name = #{arg0} and emp_salary = #{arg1}
</select>
mybaits并没有给他们创建别名,这时候可以在 mybatis-config.xml 中自己创建别名,使用的标签是typeAlias
<typeAliases>
<typeAlias type="com.ztone.pojo.Employee" alias="employee"/>
</typeAliases>
这样可以指定某个类的别名,在select 标签中resultType就可以直接使用这个别名
如果不想每个类都去指定,可以用包的方式指定
<typeAliases>
<package name="com.ztone.pojo"/>
</typeAliases>
这样这个包下的所有类的别名就是类的首字母小写,在这个前提下,可以用 @Alias("xxxxx") 指定某个类特殊的别名
在查询时,数据库中列名是下划线格式,而实体类中是驼峰式命名,如果手动起别名就无法映射。但手动起别名还是有些费劲。
可以在 mybatis-config.xml 中开启驼峰自动映射,就不用起别名,直接用*代替,或用驼峰式命名即可。
在settings标签中
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
mapUnderscoreToCamelCase属性值默认是false,设置为true 开启
如果返回的数据不是定义的实体类中有的属性,那么可以用 map 去接值。也就是 resultType 的值是 map
用map接值,列名是map的key,结果是map的值
如果返回值是list,那么resultType就是list集合中的泛型。
原因是mybatis的底层用的是 ibatis,ibatis的查询方法有两个,selectOne和 selectList。
selectOne 调用的也是 selectList,所以在底层就是返回了 集合,所以直接指定泛型即可。
5.主键回显和自动提交事务
当执行DML(插入、更新、删除)操作时,一定要提交事务,数据库中的数据才能发生变化,在执行 openSession 方法是自动开启事务,但是在完成操作后,还需要调用 sqlSession的 commit方法提交事务。
另一种方式是自动提交事务,就是在调用 openSession时传入 true,表示自动提交事务,就不用自己手动调用commit方法了
SqlSession sqlSession = sqlSessionFactory.openSession(true);
主键回显就是,在执行完插入语句后,主键如果是自动增长的,那么该如何获取这个主键的值?
在insert 标签中 加入三个属性
-
useGenerateKeys 把值设置为true,就表示需要接收自增长主键的值
-
keyColumn 数据库中对应的主键
-
keyProperty 把主键赋值给哪个属性
<insert id="insertEmpMap" useGeneratedKeys="true" keyColumn="emp_id" keyProperty="empId">
insert into t_emp(emp_name, emp_salary) values(#{name}, #{salary});
</insert>
如果主键不是自增长的,而是自己传入的值,该如何主键回显呢?
如果使用 UUID作为 主键,手动传入方式如下:
public void test_01() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = new Teacher();
teacher.settId(UUID.randomUUID().toString().replace("-",""));
teacher.settName("lalala");
int i = mapper.insertTeacher(teacher);
sqlSession.close();
}
如果交给mybatis去维护,就不需要自己手动创建这个UUID,可以在insert标签里面使用 selectKey去查询,他有三个属性
-
order 有两个值 before和 after,分别表示在 插入语句之前执行还是之后执行
-
resultType 返回值的类型,也就是selectKey标签中语句返回值的类型
-
keyProperty 查询结果赋值给哪个属性(实体类的属性)
<insert id="insertTeacher">
<selectKey order="BEFORE" resultType="string" keyProperty="tId">
select UUID();
</selectKey>
insert into teacher(t_id, t_name) values(#{tId},#{tName})
</insert>
6.resultMap
当数据库列和实体类的属性不一致时,可以使用开启 驼峰命名自动映射,也可以手动映射,用到的标签就是resultMap
<resultMap id="tMap" type="teacher">
<id column="t_id" property="tId"/>
<result column="t_name" property="tName"/>
</resultMap>
<select id="queryByid" resultMap="tMap">
select * from teacher where t_id = #{id}
</select>
在select标签中用resultMap 指定自定义映射,值就是resultMap的id
resultMap标签的type属性是返回值的类型
里面的id标签表示数据库主键的映射,result表示其他列的映射。