一、MyBatis的Dao层实现
1)代理开发方式
以前我们使用dao层,自己要写dao接口和dao实现类,但是Mybatis可以只有接口(类似dao),没有实现;实现实际上是动态代理对象,框架帮我生成
这个”全限定名还没改↓”
(xml配置的namespace = 接口的全限定名)
代码实现:
①配置Mapper
<mapper namespace="com.itheima.dao.UserMapper"> //接口全限定名
<!--查询所有User(无参)-->
<select id="findAll" resultType="user">
select * from USER
</select>
<!--根据id查询User(参数int id)-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
②定义接口
public interface UserMapper {
public List<User> findAll() throws IOException;
public User findById(int id);
}
③测试代码
public class Demo01 {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//执行SQL
List<User> userList = mapper.findAll();
//执行SQL、
User user = mapper.findById(1);
System.out.println(userList);System.out.println(user);
//释放资源
sqlSession.close();
}
}
2)Mybatis映射文件深入:动态SQL
1)if(重要)
业务场景:用于筛选条件操作数据库,条件不确定
可能1个,可能多个,可能没有
select * from user
select * from user where id=?
select * from user where id=? and username=?
select * from user where id=? and username =? and password=?
Mapper配置文件
<mapper namespace="com.itheima.dao.UserMapper">
<select id="findByConditon" resultType="user" parameterType="user">
select * from USER
<where>
<if test="id!=0">
and id = #{id}
</if>
<if test="username!=null"> //属性名称
and username = #{username}
</if>
<if test="password!=null">
and password = #{password}
</if>
</where>
</select>
<where>附加条件</where>
如果附加条件不满足就不进行SQL语句拼接,如果全部满足<where>标签以及标签内等于没有
接口:
public List<User> findByConditon(User user);
测试:
@org.junit.Test
public void Demo02() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//模拟封装好请求参数的user
User condition = new User();
condition.setId(2);
// condition.setUsername("zhangsan");
// condition.setPassword("123");
//执行SQL
List<User> user = mapper.findByConditon(condition);
System.out.println(user);
2)foreach
业务场景:循环执行sql的拼接操作
select * from user where id = 1 or id = 2 ,id =3:在1-3之内查询: 有什么就查什么,没有就不查询:
等于
select * from user id in(1,2,3)因此在( )之内,也是不动态的,不确定的。
Mapper配置文件
<mapper namespace="com.itheima.dao.UserMapper">
<select id="findByIds" parameterType="list" resultType="user">
select * from user <!--where id in (1,2,3)-->
<where>
<foreach collection="list" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
接口:
public List<User> findByIds(List<Integer> ids);//也可以是“数组”,因为( )里面可能有多个id
测试:
@org.junit.Test
public void Demo02() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//模拟封装参数的List集合
List<Integer> ids = new ArrayList<>();
ids.add(1);
// ids.add(2);
// ids.add(3);
//执行SQL
List<User> user = mapper.findByIds(ids);
System.out.println(user);
sqlSession.close();
}
解析:
- parameterType=“list”:list是框架定义好的别名
- collection:翻译“集合”,这里填你传入参数的类型,(可以填集合,也可以填数组(数组填“arrays”))
- open:从哪里开始
- close:从哪里结束
- item:翻译“项”,意思是从collection中取出的每一项的值
- separator:分隔符
select * from user where id in(1,2,3) = select * from user where “open + item + separator + close”
3)抽取重复的sql
抽取:<sql id=“selectUser”>select * from user</sql>
引入:<include refid=“selectUser”></include>
Mapp配置文件
二、Mybatis核心配置文件深入
1)typeHandlers标签
类型转换器,java数据类型
转 数据库的数据类型
,或者 数据库数据类型
转 java数据类型
。
如果要特将某个java类型
能够转数据库数据类型
就要自定义,下面是预处理器
帮我们转换的。
下面使用代码的形式解析:
目的:将java的Date类型
存进 数据库bigint数据类型
中;操作数据库时,将返回bigint类型的数据
又转回成 Date类型
,返回给java
解决:定义一个类型转换器
:将Date类型数据
转换成毫秒值的类型
存进数据库中;数据库返回时,又将 毫秒值
转Date
①数据库:
②自定义转换器:继承BaseType<T>
③复写4个方法
public class DateTpyeHandler extends BaseTypeHandler<Date> {//<T>:T为你要转换的数据类型
//将java类型 转换成 数据库字段的数据类型
@Override //int i:为Date参数的位置(执行SQL中传入的参数位置)
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
//将Date转换成毫秒值
long time = date.getTime();
//设置参数,设置要转换的毫秒值
preparedStatement.setLong(i,time);
}
//将数据库字段数据类型 转换成 java类型
//String:需要转换数据类型的字段名称
//ResultSet:数据库查询出来的结果集
@Override
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
//获取结果集中需要转换的数据类型(long)
long aLong = resultSet.getLong(s);
//转换成Date类型
Date date = new Date(aLong);
return date;
}
//将数据库字段数据类型 转换成 java类型
//int i:需要转换数据类型的字段位置
@Override
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
//获取结果集中需要转换的数据类型(long)
long aLong = resultSet.getLong(i);
//转换成Date类型
Date date = new Date(aLong);
return date;
}
//将数据库字段数据类型 转换成 java类型
//int i:需要转换数据类型的字段位置
@Override
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
//从CallableStatement中获取需要转换的数据类型(long)
long aLong = callableStatement.getLong(i);
//转换成Date类型
Date date = new Date(aLong);
return date;
}
}
④MyBatis中注册转换器
注意配置与配置之间的 配置顺序
<!--注册类型转换器-->
<typeHandlers>
<typeHandler handler="com.itheima.handler.DateTpyeHandler"/>
</typeHandlers>
⑤测试
Mapper配置:
<mapper namespace="com.itheima.dao.UserMapper">
<sql id="selectUser">select * from user</sql>
<!--插入数据:测试java类型转数据库类型数据-->
<insert id="save" parameterType="user">
insert into user values (#{id},#{username},#{password},#{birthday})
</insert>
<!--查询数据:测试数据库转java类型数据-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
测试类:
//数据库转java类型数据
@org.junit.Test
public void Demo03() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//执行SQL
User user = mapper.findById(10);
System.out.println(user);
sqlSession.close();
}
//java转数据库类型数据
@org.junit.Test
public void Demo04() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//模拟封装好请求参数的user
User user = new User();
user.setUsername("刘德华");
user.setPassword("123");
user.setBirthday(new Date());
//执行SQL
mapper.save(user);
System.out.println(user);
sqlSession.close();
}
2)plugins标签
plugins(插件)可以导入插件拓展Mybatis功能,下面 演示分页插件的功能
①pom.xml:导入分页插件
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
②Mybatis核心配置文件:配置分页插件
<!--配置分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/> <!--指定方言:(指定什么数据库)因为不同数据库sql命令可能不一样-->
</plugin>
</plugins>
③测试
@org.junit.Test
public void Demo05() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//设置分页相关参数 参数(当前页码,每页显示条数)
PageHelper.startPage(1,3);//显示第1页的3条数据
//执行SQL
List<User> users = mapper.findAll();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
分页插件:获取其他相关参数
@org.junit.Test
public void Demo05() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//设置分页相关参数 参数(当前页码,每页显示条数)
PageHelper.startPage(2,3);//显示第1页的3条数据
//执行SQL
List<User> users = mapper.findAll();//查询所有user
for (User user : users) {
System.out.println(user);
}
//获取分页相关的参数
PageInfo<User> info = new PageInfo<User>(users);//<T>:你要进行分页的Bean对象 参数:返回查询user的集合
System.out.println("当前页码:"+info.getPageNum());
System.out.println("每页显示条数:"+info.getPageNum());
System.out.println("总条数:"+info.getTotal());
System.out.println("总页码:"+info.getPages());
System.out.println("上一页:"+info.getLastPage());
System.out.println("下一页:"+info.getNextPage());
System.out.println("第一页:"+info.getFirstPage());
System.out.println("最后一个:"+info.getLastPage());
System.out.println("是否为第一页:"+info.isIsFirstPage());
System.out.println("是否为最一页:"+info.isIsLastPage());
//....
sqlSession.close();//释放资源
}