▲ 共有4种加载Mapper的方式:
1、2. 明确指定XML Mapper的位置(resource与url二者选其一)
<mapper resource|url=“被加载XML Mapper文件” …/>
<mappers>
<!-- mapper文件负责管理MyBatis的SQL语句 -->
<mapper resource="org/itcheng/app/dao/NewsMapper.xml" />
</mappers>
<mappers>
<!-- mapper文件负责管理MyBatis的SQL语句 -->
<mapper url="file:///D:/mytool/javagongju/fengkuangjavajiangyi/javassmday03/10objectFactory/src/org/itcheng/app/dao/NewsMapper.xml" />
</mappers>
<mappers>
<!-- mapper文件负责管理MyBatis的SQL语句 -->
<mapper resource="org.itcheng.app.dao.NewsMapper" />
</mappers>
<mappers>
<!-- 加载指定包下面所有Mapper -->
<package name="org.itcheng.app.dao" />
</mappers>
类型处理器的作用:负责完成数据库中数据类型与Java类型之间的相互转换。
▲ MyBatis内置的数据类型
常见的Java类型与常见数据库中数据类型之间的转换,MyBatis已经提供了类型处理器。
▲ 自定义的数据类型处理器
也属于MyBatis的扩展点。
比如程序,需要完成varchar <----> Name
(1)开发自定义类型处理器
对象工厂类要实现TypeHandler接口,实际上会通过继承BaeTypeHandler实现类
根据需要重写它指定的4个方法
/*
* java.sql.ResultSet 表示通过结果集取数据
* java.sql.CallableStatement表示通过CallableStatement取数据
*
* int columnIndex 表示根据列索引进行获取
* String columnName 表示根据列名进行获取
* */
// 将数据库的取出的数据类型转换Java类型
@Override
public Name getNullableResult(ResultSet rs, String columnName) throws SQLException
?
?// 将数据库的取出的数据类型转换Java类型
@Override
public Name getNullableResult(ResultSet rs, int columnIndex) throws SQLException
??
// 将数据库的取出的数据类型转换Java类型
@Override
public Name getNullableResult(CallableStatement cs, int columnIndex) throws SQLException
??
// Java类型转换数据库所需的类型
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Name parameter, JdbcType jdbcType) throws SQLException
(2)配置自定义类型处理器
需要使用如下元素来配置自定义的类型处理器
<typeHandler handler="org.itcheng.app.NameTypeHandler" jdbcType="" javaType=""/>
既可在类型处理器的代码上用注解来指定它能处理哪些类型(@MappedJdbcTypes,@MappedTypes),也能在XML配置中指定(typeHandler 标签中属性jdbcType, javaType), 如果两处都指定,XML配置中指定的生效.
User类中有个引用类型Name,mybatis无法将对象Name保存到数据库具体的字段
需要提供自定义类型装换器
2个Bean类
package org.itcheng.app.domain;
public class User
{
private Integer id;
private Name name;
private String password;
//set和get方法,有参无参构造器,toString方法
}
package org.itcheng.app.domain;
public class Name
{
private String first;
private String last;
//set和get方法,有参无参构造器,toString方法
自定义类型装换器
package org.itcheng.app;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.itcheng.app.domain.Name;
@MappedJdbcTypes(JdbcType.VARCHAR) // 告诉MyBatis,说明该类型转换器只处理数据库的VARCHAR类型
@MappedTypes(Name.class) // 告诉MyBatis,说明该类型转换器只处理Java的Name类型
public class NameTypeHandler extends BaseTypeHandler<Name>
{
/*
* java.sql.ResultSet 表示通过结果集取数据
* java.sql.CallableStatement表示通过CallableStatement取数据
*
* int columnIndex 表示根据列索引进行获取
* String columnName 表示根据列名进行获取
*
* */
// 将数据库的取出的数据类型转换Java类型
@Override
public Name getNullableResult(ResultSet rs, String columnName)
throws SQLException
{
// 取出实际的值
String val = rs.getString(columnName);
//按照"-"进行分隔
String[] tokens = val.split("-");
// 将值封装Name对象
Name name = new Name(tokens[0], tokens[1]);
return name;
}
// 将数据库的取出的数据类型转换Java类型
@Override
public Name getNullableResult(ResultSet rs, int columnIndex)
throws SQLException
{
// 取出实际的值
String val = rs.getString(columnIndex);
String[] tokens = val.split("-");
// 将值封装Name对象
Name name = new Name(tokens[0], tokens[1]);
return name;
}
// 将数据库的取出的数据类型转换Java类型
@Override
public Name getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException
{
// 取出实际的值
String val = cs.getString(columnIndex);
String[] tokens = val.split("-");
// 将值封装Name对象
Name name = new Name(tokens[0], tokens[1]);
return name;
}
// Java类型转换数据库所需的类型
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
Name parameter, JdbcType jdbcType) throws SQLException
{
ps.setString(i, parameter.getFirst() + "-" + parameter.getLast());
}
}
主配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- configuration 配置根元素 -->
<configuration>
<typeAliases>
<package name="org.itcheng.app.domain"/>
</typeAliases>
<!-- 配置自定义的类型处理器 -->
<typeHandlers>
<typeHandler handler="org.itcheng.app.NameTypeHandler"/>
</typeHandlers>
<!-- environments 用于配置多个数据库环境 default用于指定默认环境-->
<environments default="mysql">
<!-- environment 配置一个数据库环境 id数据库唯一标识-->
<environment id="mysql">
<!-- transactionManager 配置事务类型:JDBC或Managed,此时的JDBC等都是实现类的缩写 -->
<transactionManager type="JDBC" />
<!-- 配置数据库连接池,POOLED也是一个实现类的缩写 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 加载指定包下面所有Mapper -->
<package name="org.itcheng.app.dao" />
</mappers>
</configuration>
映射文件
<?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">
<!-- 根元素是mapper,该元素的namespace属性值相当于该mapper的唯一标识 -->
<mapper namespace="org.itcheng.app.dao.UserMapper">
<!-- SQL的id需要与Mapper接口的方法名相同 -->
<insert id="saveUser">
insert into user_inf values (null, #{name}, #{password})
</insert>
<!-- select必须指定resultType或resultMap两个属性的其中之一
此处指定结果的每行记录应该映射成News对象
由于News对象的三个属性分别为id、title、content
所以此处查询出来的结果集的列别名也被定义成id、title、content
这样才能保证MyBatis执行同名映射
-->
<select id="findUsers" resultType="user">
select user_id id, user_name name, password from user_inf where user_id > #{id}
</select>
</mapper>
主类
package lee;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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.itcheng.app.dao.UserMapper;
import org.itcheng.app.domain.Name;
import org.itcheng.app.domain.User;
public class UserManager
{
// SqlSessionFactory应该是应用级别
private static SqlSessionFactory sqlSessionFactory;
public static void main(String[] args) throws IOException
{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 1. 创建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 保存消息
saveUser(sqlSession);
// 查询消息
// selectUsers(sqlSession);
}
public static void saveUser(SqlSession sqlSession)
{
User user = new User(null, new Name("己","妲"), "888888");
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.saveUser(user);
// 4. 提交事务
sqlSession.commit();
// 5. 关闭资源
sqlSession.close();
}
public static void selectUsers(SqlSession sqlSession)
{
// 此处的NewsMapper只是一个接口
// MyBatis会使用JDK的动态代理为Mapper接口生成实现类
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<?> list = userMapper.findUsers(-1);
list.forEach(e -> {
Name name = ((User) e).getName();
System.out.println(name.getFirst());
System.out.println(name.getLast());
});
System.out.println(list);
// 4. 提交事务
sqlSession.commit();
// 5. 关闭资源
sqlSession.close();
}
}
执行插入语句
DEBUG [main] org.itcheng.app.dao.UserMapper.saveUser ==> Preparing: insert into user_inf values (null, ?, ?)
DEBUG [main] org.itcheng.app.dao.UserMapper.saveUser ==> Parameters: 己-妲(String), 888888(String)
DEBUG [main] org.itcheng.app.dao.UserMapper.saveUser <== Updates: 1
执行查询语句
DEBUG [main] org.itcheng.app.dao.UserMapper.findUsers ==> Preparing: select user_id id, user_name name, password from user_inf where user_id > ?
DEBUG [main] org.itcheng.app.dao.UserMapper.findUsers ==> Parameters: -1(Integer)
DEBUG [main] org.itcheng.app.dao.UserMapper.findUsers <== Total: 1
己
妲
[User [id=1, name=Name [first=己, last=妲], password=888888]]