7. mybatis映射文件介绍
映射文件介绍
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
1. log4j
程序运行的时候我们需要通过日志来记录程序的运行情况,这些日志可以帮助我们分析程序代码及错误排查等.....
1.1 添加相关的依赖
<!-- log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
1.2 创建log4j.properties文件
创建一个日志的属性文件,在该文件中配置日志的相关信息
log4j.rootCategory=All, stdout , R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\\logs\\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
1.3 使用
package com.bobo;
import com.bobo.dao.UserMapper;
import com.bobo.pojo.User;
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.apache.log4j.Logger;
import java.io.InputStream;
import java.util.List;
public class AppStart1 {
static Logger logger = Logger.getLogger(AppStart1.class);
public static void main(String[] args) throws Exception{
logger.error("log:error");
logger.warn("log:warn");
logger.info("log:info");
logger.debug("log:debug");
// 1.加载全局配置文件
InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
// 2.获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.根据SqlSessionFactory获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession获取Dao接口的代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> list = mapper.query(26);
for (User user : list) {
System.out.println(user + ":" + user.getFavorites());
}
// 5.提交资源并关闭连接
sqlSession.commit();
sqlSession.close();
}
}

2.传入参数
2.1 ${}和#{}的区别
#{}的使用方式
sql
<select id="query" parameterType="int" resultType="UsER">
select * from t_user where id = #{id}
</select>
执行后

${}的使用
sql
<select id="query" parameterType="int" resultType="UsER">
select * from t_user where id = ${id}
</select>
执行后抛出了异常信息

${}的使用我们必须在接口的形参中添加@Param
注解修饰
public interface UserMapper {
int addUser(User user);
List<User> query(@Param("id") Integer id);
}
再执行就可以了

通过日志文件可以看到两种方式执行的SQL语句是有区别的,一种是使用了占位符,一种是直接赋值的。
由于MyBatis底层还是Jdbc操作,而Jdbc操作数据库传递数据时有两种方式,一种是Statement,还一种是PreparedStatement方式,使用Statement会有SQL注入的风险,而PreparedStatement通过占位符的方式就可以避免SQL注入的情况。
在MyBatis中对应的两种使用方式的体现就是#{}和${}的方式,显然#{}对应的是PreparedStatement,而${}对应的是Statement。显然在MyBatis中我们更加推荐使用#{}
2.2 多个参数
定义update标签
<update id="updateUser" >
update t_user set username = #{username} where id = #{id}
</update>
定义的接口
package com.bobo.dao;
import com.bobo.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Dao的接口
*/
public interface UserMapper {
int addUser(User user);
List<User> query(@Param("id") Integer id);
int updateUser(String userName,Integer id);
}
测试 执行
package com.bobo;
import com.bobo.dao.UserMapper;
import com.bobo.pojo.User;
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 java.io.InputStream;
import java.util.Arrays;
public class AppStart3 {
public static void main(String[] args) throws Exception{
// 1.加载全局配置文件
InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
// 2.获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.根据SqlSessionFactory获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession获取Dao接口的代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser("赵六",27);
// 5.提交资源并关闭连接
sqlSession.commit();
sqlSession.close();
}
}

根据错误提示我们可以在映射文件中通过 [arg1,arg0,param1,param2]来获取传递的多个参数



如果我不想使用系统提供的,而是自定义参数名称同样可以通过@Param
实现


2.3 包装对象
我们传递的是一个包装类对象,针对这种情况我们应该怎么获取相关的参数
package com.bobo.pojo;
/**
* 包装类
*/
public class UserWrapper {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
如果我们传递的是个包装对象,那么我们可以通过"."存取器来处理相关的情况


3.返回数据
3.1 resultType
通过resultType设置操作的返回结果类型,如果返回的是基本数据类型,那么我们可以直接写Java中的基本数据类型即可。如果返回的是一个对象或者集合,并且对象中的属性和查询的字段名一一对应,那么resultType可以直接写一个对象
3.2 resultMap
resultMap主要用来解决属性名和字段名不一致以及一对多、一对一查询等问题。字段名不一致时,首先可以通过取别名的方式解决

Java类中的属性name和表结构中的字段userName不同


第一种解决方案就是添加别名
<select id="query" parameterType="int" resultType="UsER">
select
id
,username name
,address
,gender
,favorites
from t_user where id = ${id}
</select>

第二种解决方式是通过resultMap来指定表结构中的字段和Java类中的属性的对应关系
<resultMap id="baseMap" type="user">
<id column="id" property="id"/>
<result column="username" property="name"/>
<result column="address" property="address"/>
<result column="gender" property="gender"/>
<result column="favorites" property="favorites" />
</resultMap>
<select id="queryAll" resultMap="baseMap">
select * from t_user
</select>

4.主键回写
一般情况下,主键的两种生成方式
- 主键自增
- 自定义主键(一般使用UUID)

4.1 主键回填
<insert id="addUser" parameterType="UsER" useGeneratedKeys="true" keyProperty="id">
insert into t_user (username,address,gender,favorites)values(#{name},#{address},#{gender},#{favorites})
</insert>
useGeneratedKeys:使用生成的主键
keyProperty:将生成的主键的值保存到对象的id属性中


4.2 selectKey
另外一种方式可以利用MySQL自带的last_insert_id() 函数来获取刚刚插入的id
<insert id="addUserWrapper" parameterType="userwrapper">
<selectKey keyProperty="user.id" resultType="int">
select LAST_INSERT_ID()
</selectKey>
insert into t_user(username,address,gender)values(#{user.name},#{user.address},#{user.gender})
</insert>
