第一节 MyBatis的Dao
第一种:dao与实现类编写【了解,有更好的方法】
dao实现类编写
package com.it.dao.impl;
import com.it.dao.UserDao;
import com.it.model.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
/**
* @ClassName UserDaoImpl
* @Author shuyy
* @Date 2020/9/22
**/
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
//直接通过有参构造方法注入,也可以通过get/set
public UserDaoImpl() {
}
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public void save(User user) {
//获取session
SqlSession sqlSession = sqlSessionFactory.openSession();
//插入数据
sqlSession.insert("insertUser",user);
sqlSession.commit();
sqlSession.close();
}
@Override
public User findUserById(int id) {
//获取session
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("findUserById",id);
sqlSession.close();
return user;
}
}
- User.xml
test测试
package com.it.test;
import com.it.dao.UserDao;
import com.it.dao.impl.UserDaoImpl;
import com.it.model.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
/**
* @ClassName Demo02
* @Author shuyy
* @Date 2020/9/22
**/
public class Demo03 {
//SqlSession sqlSession;
SqlSessionFactory sessionFactory;
@Before
public void before() throws IOException {
System.out.println("before...获取session");
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
/*sqlSession = sessionFactory.build(inputStream).openSession();*/
}
/*@After
public void after(){
System.out.println("after...关闭session");
//5.关闭SqlSession
sqlSession.close();
}*/
@Test
public void test1(){
//调用dao
UserDao userDao = new UserDaoImpl(sessionFactory);
User user1 = userDao.findUserById(1);
System.out.println(user1);
System.out.println("==============");
User user2 = new User("shu07", "男", new Date(), "杭州市");
userDao.save(user2);
}
}
第二种:不写dao实现类,使用mapper代理方式实现【常用】
- Mapper代理的开发方式,程序员只需要编写mapper接口(相当于dao接口)即可。Mybatis会自动的为mapper接口生成动态代理实现类。
- 不过要实现mapper代理的开发方式,需要遵循一些开发规范。
开发规范
- mapper接口的全限定名要和mapper映射文件的namespace的值相同。
- mapper接口的方法名称要和mapper映射文件中的statement的id相同;
- mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
- mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;
- 通过规范式的开发mapper接口,可以解决原始dao开发当中存在的问题:
1. 可以去除重复的模板代码;
2. 剩下去不掉的操作数据库的代码,其实就是一行代码。这行代码中硬编码的部分,通过第一和第二个规范就可以解决。
第一步:重写配置文件
- 重新写个UserMapper配置文件和定义mapper映射文件UserMapper.xml(内容同User.xml,除了namespace的值),放到新创建的目录mapper下。
- dao
package com.it.mapper;
import com.it.model.User;
public interface UserMapper {
int save(User user);
User findUserById(int id);
}
- UserMapper.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">
<mapper namespace="com.it.mapper.UserMapper">
<!--如果主键是mysql自增机制实现的,不需要给主键赋值,否则必须要赋值,否则报错-->
<insert id="save" parameterType="com.it.model.User">
insert into user (username,sex,birthday,address)
values (#{username},#{sex},#{birthday},#{address})
</insert>
<select id="findUserById" parameterType="int" resultType="com.it.model.User">
SELECT * FROM USER WHERE id = #{id}
</select>
</mapper>
第二步:添加映射配置文件
第三步:测试(无需写dao的实现类)
package com.it.test;
import com.it.mapper.UserMapper;
import com.it.model.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.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
/**
* @ClassName Demo02
* @Author shuyy
* @Date 2020/9/22
**/
public class Demo04 {
SqlSession sqlSession;
@Before
public void before() throws IOException {
System.out.println("before...获取session");
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
sqlSession = sessionFactory.openSession();
}
@After
public void after(){
System.out.println("after...关闭session");
//5.关闭SqlSession
sqlSession.close();
}
@Test
public void test1(){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println(userMapper);//返回的是一个代理对象
//获取数据
System.out.println(userMapper.findUserById(1));
//保存数据
User user = new User("shu10", "男", new Date(), "汕头市");
userMapper.save(user);
sqlSession.commit();//增删改记得提交事务
}
}
第二节 全局配置文件与其它一些配置
2.1 properties数据库配置文件
1. 在src下配置个db.properties文件
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///mybatis_day01
username=root
password=root
2. 修改全局配置文件SqlMapConfig.xml
<?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>
<!--读取db.properties-->
<properties resource="db.properties"></properties>
<!-- 配置mybatis的环境信息 -->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务控制,由mybatis进行管理,如果不配置会报错 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源,采用dbcp连接池 -->
<dataSource type="POOLED">
<!--使用${},可以引用加载的java配置文件中的信息-->
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<!--<mapper resource="com/it/sqlmap/User.xml"></mapper>-->
<mapper resource="com/it/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
3. 测试配置是否成功
2.2 setting【了解】
- 就是通过 name 和 value 来配置一些功能
具体配置详解
2.3 typeAliases【别名配置】
- 别名的使用是为了在映射文件中,更方便的去指定参数和结果集的类型,不用再写很长的一段全限定名。
mybatis支持的别名
自定义别名
- 使用测试
2.4 mybatis加载映射文件的几种方式
<!--加载映射文件-->
<mappers>
<!--<mapper resource="com/it/sqlmap/User.xml"></mapper>-->
<!--第一种:写映射文件名-->
<!--<mapper resource="com/it/mapper/UserMapper.xml"></mapper>-->
<!--第二种:使用完全限定路径【一般不用】-->
<!--<mapper url="file:///D:\MyBatis_day01\src\com\it\mapper\UserMapper.xml"></mapper>-->
<!--第三种:写类名(使用mapper接口的全限定名)
一定要有个同名映射文件与之对应,如果没有,在UserMapper接口中声明注解,否则报错-->
<!--使用注解配置时,要删除或改名映射文件,否则报错-->
<!--注意:不使用注解时,此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下-->
<!--<mapper class="com.it.mapper.UserMapper"></mapper>-->
<!--第四种:写包名【推荐使用】
注册指定包下的所有映射文件-->
<!--注意:此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下-->
<package name="com.it.mapper"/>
</mappers>
- 使用注解配置的注意事项(直接在接口上使用注解配置)
public interface UserMapper {
@Insert("insert into user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})")
int save(User user);
@Select("SELECT * FROM USER WHERE id = #{id}")
User findUserById(int id);
}
- (使用注解配置时)必须要改名或删除同名映射文件,否则报错
- 使用包配置注册时(也可以同时使用注解)(配置同上),但是涉及复杂的操作时不建议使用注解,还是用回映射文件
- 此时接口名与映射文件名要保持一致,且放在同一目录下
第三节 mybatis映射文件的一些解释
3.1 输入映射ParameterType
- 指定输入参数的java类型,可以使用别名或者类的全限定名。它可以接收简单类型、POJO对象、HashMap
- 简单类型:java的基本类型,四类八种
1. 传递简单类型
- 根据用户ID查询用户信息
2. 传递POJO对象
3. 传递POJO包装对象
- 开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
vo:键值对对象,相对于key,value
po:persist object 持久化对象
pojo:简单的java对象
entity:实体
以上就是一些模型
- 定义pojo包装类(User与Orders属性与数据库字段对应),并提供get/set
package com.it.vo;
import com.it.model.Orders;
import com.it.model.User;
public class UserQueryVo {
private User user;
private Orders orders;
public Orders getOrders() {
return orders;
}
public void setOrders(Orders orders) {
this.orders = orders;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
- 修改UserMapper.java
- 修改UsrMappler.xml
<!--通过包装类查询用户-->
<select id="findUserByUserQueryVo" parameterType="UserQueryVo" resultType="user">
select u.*,o.* from user u,orders o where u.id = #{user.id} and o.number = #{orders.number}
</select>
- 记得加上包别名
- 测试
package com.it.test;
import com.it.mapper.UserMapper;
import com.it.model.Orders;
import com.it.model.User;
import com.it.vo.UserQueryVo;
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.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @ClassName Demo02
* @Author shuyy
* @Date 2020/9/22
**/
public class Demo05 {
SqlSession sqlSession;
@Before
public void before() throws IOException {
System.out.println("before...获取session");
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
sqlSession = sessionFactory.openSession();
}
@After
public void after(){
System.out.println("after...关闭session");
//5.关闭SqlSession
sqlSession.close();
}
@Test
public void test1(){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//System.out.println(userMapper);//返回的是一个代理对象
//通过模型的包装类来查询用户
UserQueryVo queryVo = new UserQueryVo();
User user = new User();
user.setId(1);
queryVo.setUser(user);
Orders orders = new Orders();
orders.setNumber("1000010");
queryVo.setOrders(orders);
List<User> list = userMapper.findUserByUserQueryVo(queryVo);
System.out.println(list);
//sqlSession.commit();//增删改记得提交事务
}
}
4. 传递map对象
- 修改UserMapper.java
- 修改UserMapper.xml
- 由于配置${username}冲突,修改了数据库配置文件
- 测试
@Test
public void test2(){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//System.out.println(userMapper);//返回的是一个代理对象
//通过 Map 来查询用户
//查询条件
Map<String,Object> map = new HashMap<String,Object>();
map.put("username","shu03");
map.put("sex","男");
List<User> list = userMapper.findUserByMap(map);
System.out.println(list);
//sqlSession.commit();//增删改记得提交事务
}
3.2 输出映射resultType/resultMap
resultType
(下面这些情况将在使用resultMap时演示)
- 使用resultType进行结果映射时,查询的列名和映射的pojo属性名完全一致,该列才能映射成功。
- 如果查询的列名和映射的pojo属性名全部不一致,则不会创建pojo对象;
- 如果查询的列名和映射的pojo属性名有一个一致,就会创建pojo对象。
1. 输出简单类型
- 当输出结果只有一列时,可以使用ResultType指定简单类型作为输出结果类型。
- 如查询user表中男性用户有多少个?
-
UserMapper.java添加方法(使用包装类参数)
-
UserMapper.xml写sql
-
使用包装类测试
2. 输出单个pojo对象
- 前面使用过,不再赘述
3. 输出POJO列表
总结
- 输出单个pojo对象和pojo列表时,mapper映射文件中的resultType的类型是一样的,mapper接口的方法返回值不同。
- 同样的mapper映射文件,返回单个对象和对象列表时,mapper接口在生成动态代理的时候,会根据返回值的类型,决定调用selectOne方法还是selectList方法。
resultMap
- 如果查询出来的列名和属性名不一致,通过定义一个resultMap将列名和pojo属性名之间作一个映射关系。
- 步骤:
- 定义resultMap
- 使用resultMap作为statement的输出映射类型
- 这样是一致(不一致就是改动一下列名,或给字段起别名)
- UserMapper.java中添加一个方法
- 在UserMapper.xml中配置该方法的sql
- 这样给数据库字段起别名查询,形成字段不一致(也可以直接修改表的列名),会导致查询不出结果,因为没有字段匹配
- 如果有一个字段匹配也会有结果,而不是null
- 所以这里就要配置一个resultMap来声明字段别名,这样配置后就有值了