Mybatis
01.mybatis介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatement、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
02.jdbc问题总结如下:
1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
2、 Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4、 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
03.Mybatis架构
1、 mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
04.入门程序
SqlMapConfig.xml
配置数据库连接池,引入SQL映射文件。
<?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>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.142.11:3306/mybatis?characterEncoding=utf-8"/>
<property name="username" value="mycon"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="User.xml"/>
</mappers>
</configuration>
User.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">
<!-- namespace:命名空间,做sql隔离 -->
<mapper namespace="test">
<!--
id:sql语句唯一标识
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}占位符:起到占位作用,如果传入的是基本类型(string,long,double,int,boolean,float等),那么#{}中的变量名称可以随意写.
-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.my.pojo.User">
select * from user where id=#{id}
</select>
<!--
如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所以映射文件中应该配置成集合泛型的类型
${}拼接符:字符串原样拼接,如果传入的参数是基本类型(string,long,double,int,boolean,float等),那么${}中的变量名称必须是value
注意:拼接符有sql注入的风险,所以慎重使用
-->
<select id="findUserByUserName" parameterType="java.lang.String" resultType="com.my.pojo.User">
select * from user where username like '%${value}%'
</select>
<!--
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性.....
如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
-->
<insert id="insertUser" parameterType="com.my.pojo.User" >
<!-- 执行 select LAST_INSERT_ID()数据库函数,返回自增的主键
keyProperty:将返回的主键放入传入参数的Id中保存.
order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后执行是AFTER
resultType:id的类型,也就是keyproperties中属性的类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 需要增加通过select uuid()得到uuid值
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id">
select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
注意这里使用的order是“BEFORE” -->
<delete id="delUserById" parameterType="int">
delete from user where id=#{id}
</delete>
<update id="updateUserById" parameterType="com.my.pojo.User">
update user set username=#{username} where id=#{id}
</update>
</mapper>
UserTest.java
public class UserTest {
@Test
public void testFindUserById() throws Exception{
String resource = "SqlMapConfig.xml";
//通过流将核心配置文件读取进来
InputStream inputStream = Resources.getResourceAsStream(resource);
//通过核心配置文件输入流来创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建会话
SqlSession openSession = factory.openSession();
//第一个参数:所调用的sql语句= namespace+.+sql的ID
User user = openSession.selectOne("test.findUserById", 1);
System.out.println(user);
openSession.close();
}
@Test
public void testFindUserbyUserName() throws Exception{
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession = factory.openSession();
List<User> list = openSession.selectList("test.findUserByUserName", "王");
System.out.println(list);
openSession.close();
}
@Test
public void testInsertUser() throws Exception{
String resource = "SqlMapConfig.xml";
//通过流将核心配置文件读取进来
InputStream inputStream = Resources.getResourceAsStream(resource);
//通过核心配置文件输入流来创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建会话
SqlSession openSession = factory.openSession();
User user = new User();
user.setUsername("赵四");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("北京昌平");
System.out.println("====" + user.getId());
openSession.insert("test.insertUser", user);
//提交事务(mybatis会自动开启事务,但是它不知道何时提交,所以需要手动提交事务)
openSession.commit();
openSession.close();
System.out.println("====" + user.getId());
}
@Test
public void testDelUserById()throws Exception{
String resource = "SqlMapConfig.xml";
//通过流将核心配置文件读取进来
InputStream inputStream = Resources.getResourceAsStream(resource);
//通过核心配置文件输入流来创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建会话
SqlSession openSession = factory.openSession();
openSession.delete("test.delUserById", 29);
//提交
openSession.commit();
}
@Test
public void testUpdateUserById() throws Exception{
String resource = "SqlMapConfig.xml";
//通过流将核心配置文件读取进来
InputStream inputStream = Resources.getResourceAsStream(resource);
//通过核心配置文件输入流来创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建会话
SqlSession openSession = factory.openSession();
User user = new User();
user.setId(28);
user.setUsername("王麻子");
openSession.update("test.updateUserById", user);
//提交
openSession.commit();
}
}
05.原生dao
SqlMapConfig.xml
User.xml
UserDao\UserDaoImpl
public interface UserDao {
public User findUserById(Integer id);
public List<User> findUserByUserName(String userName);
}
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
//通过构造方法注入
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(Integer id) {
//SqlSession是线程不安全的,所以要在方法体内
SqlSession openSession = sqlSessionFactory.openSession();
User user = openSession.selectOne("test.findUserById", id);
openSession.close();
return user;
}
@Override
public List<User> findUserByUserName(String userName) {
SqlSession openSession = sqlSessionFactory.openSession();
List<User> list = openSession.selectList("test.findUserByUserName", userName);
openSession.close();
return list;
}
}
UserDaoTest
public class UserDaoTest {
private SqlSessionFactory factory;
@Before
public void setUp()throws Exception{
String resource = "SqlMapConfig.xml";
//通过流将核心配置文件读取进来
InputStream inputStream = Resources.getResourceAsStream(resource);
//通过核心配置文件输入流来创建会话工厂
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById()throws Exception{
UserDao userDao = new UserDaoImpl(factory);
User user = userDao.findUserById(1);
System.out.println(user);
}
@Test
public void findUserByUserName()throws Exception{
UserDao userDao = new UserDaoImpl(factory);
List<User> listuser = userDao.findUserByUserName("小明");
System.out.println(listuser);
}
}
06.mapper代理
SqlMapConfig.xml扫描
<mappers>
<!--
使用class属性引入接口的全路径名称:
使用规则:
1. 接口的名称和映射文件名称除扩展名外要完全相同
2. 接口和映射文件要放在同一个目录下
-->
<!-- <mapper class="com.my.mapper.UserMapper"/> -->
<!-- 使用包扫描的方式批量引入Mapper接口
使用规则:
1. 接口的名称和映射文件名称除扩展名外要完全相同
2. 接口和映射文件要放在同一个目录下
-->
<package name="com.my.mapper"/>
</mappers>
UserMapper
public interface UserMapper {
public User findUserById(Integer id);
public List<User> findUserByUserName(String userName);
public void insertUser(User user);
}
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接口代理实现编写规则:
1. 映射文件中namespace要等于接口的全路径名称
2. 映射文件中sql语句id要等于接口的方法名称,(接口=方法名称)
3. 映射文件中传入参数类型要等于接口方法的传入参数类型,(参数相同)
4. 映射文件中返回结果集类型要等于接口方法的返回值类型
-->
<mapper namespace="com.my.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="com.my.pojo.User">
select * from user where id=#{id}
</select>
<select id="findUserByUserName" parameterType="String" resultType="com.my.pojo.User">
select * from user where username like '%${value}%'
</select>
<!--
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性.....
如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
-->
<insert id="insertUser" parameterType="com.my.pojo.User" >
<!-- 执行 select LAST_INSERT_ID()数据库函数,返回自增的主键
keyProperty:将返回的主键放入传入参数的Id中保存.
order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后执行是AFTER
resultType:id的类型,也就是keyproperties中属性的类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
UserMapperTest
public class UserMapperTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件读取进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过核心配置文件输入流来创建会话工厂
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
//动态代理形式中,如果返回 结果集为list,那么mybatis会在生成实现类的时候会自动调用selectlist方法
@Test
public void testFindUserById() throws Exception {
SqlSession openSession = factory.openSession();
// 通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
User user = mapper.findUserById(1);
openSession.close();
System.out.println(user);
}
@Test
public void testFindByUserName()throws Exception{
SqlSession openSession = factory.openSession();
// 通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
List<User> listUser = mapper.findUserByUserName("小雨");
openSession.close();
System.out.println(listUser);
}
@Test
public void testInsert()throws Exception{
SqlSession openSession = factory.openSession();
// 通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
User user = new User();
user.setAddress("昌平");
user.setSex("2");
user.setUsername("小雨");
mapper.insertUser(user);
System.out.println(user.getId());
//提交事务(mybatis会自动开启事务,但是它不知道何时提交,所以需要手动提交事务)
openSession.commit();
openSession.close();
}
}
07.总结
pojo:不按mvc分层,只是java bean有一些属性,还有get set方法
domain:不按mvc分层,只是java bean有一些属性,还有get set方法
po:用在持久层,还可以再增加或者修改的时候,从页面直接传入action中,它里面的java bean 类名等于表名,
属性名等于表的字段名,还有对应的get set方法
vo: view object表现层对象,主要用于在高级查询中从页面接收传过来的各种参数.好处是扩展性强
bo: 用在servie层,现在企业基本不用.
这些po,vo, bo,pojo可以用在各种层面吗
可以,也就是po用在表现层,vo用在持久层不报错,因为都是普通的java bean没有语法错误.
hibernate和mybatis区别:
hibernate:它是一个标准的orm框架,比较重量级,学习成本高.
优点:高度封装,使用起来不用写sql,开发的时候,会减低开发周期.
缺点:sql语句无法优化
应用场景:oa(办公自动化系统), erp(企业的流程系统)等,还有一些政府项目,
总的来说,在用于量不大,并发量小的时候使用.
mybatis:它不是一个orm框架, 它是对jdbc的轻量级封装, 学习成本低,比较简单
有点:学习成本低, sql语句可以优化, 执行效率高,速度快
缺点:编码量较大,会拖慢开发周期
应用场景: 互联网项目,比如电商,P2p等
总的来说是用户量较大,并发高的项目.
08.输入输出映射
<!--
mapper接口代理实现编写规则:
1. 映射文件中namespace要等于接口的全路径名称
2. 映射文件中sql语句id要等于接口的方法名称
3. 映射文件中传入参数类型要等于接口方法的传入参数类型
4. 映射文件中返回结果集类型要等于接口方法的返回值类型
-->
<mapper namespace="cn.itheima.mapper.UserMapper">
<!--
id:sql语句唯一标识
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}占位符:起到占位作用,如果传入的是基本类型(string,long,double,int,boolean,float等),那么#{}中的变量名称可以随意写.
-->
<select id="findUserById" parameterType="int" resultType="cn.itheima.pojo.User">
select * from user where id=#{id}
</select>
<!--
如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所以映射文件中应该配置成集合泛型的类型
${}拼接符:字符串原样拼接,如果传入的参数是基本类型(string,long,double,int,boolean,float等),那么${}中的变量名称必须是value
注意:拼接符有sql注入的风险,所以慎重使用
-->
<select id="findUserByUserName" parameterType="string" resultType="user">
select * from user where username like '%${value}%'
</select>
<!--
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性.....
如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
-->
<insert id="insertUser" parameterType="cn.itheima.pojo.User" >
<!-- 执行 select LAST_INSERT_ID()数据库函数,返回自增的主键
keyProperty:将返回的主键放入传入参数的Id中保存.
order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后执行是AFTER
resultType:id的类型,也就是keyproperties中属性的类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
<select id="findUserbyVo" parameterType="cn.itheima.pojo.QueryVo" resultType="cn.itheima.pojo.User">
select * from user where username like '%${user.username}%' and sex=#{user.sex}
</select>
<!-- 只有返回结果为一行一列的时候,那么返回值类型才可以指定成基本类型 -->
<select id="findUserCount" resultType="java.lang.Integer">
select count(*) from user
</select>
</mapper>
09.动态sql
If,where
<!-- 封装sql条件,封装后可以重用.
id:是这个sql条件的唯一标识 -->
<sql id="user_Where">
<!-- where标签作用:
会自动向sql语句中添加where关键字
会去掉第一个条件的and关键字
-->
<where>
<if test="username != null and username != ''">
and username like '%${username}%'
</if>
<if test="sex != null and sex != ''">
and sex=#{sex}
</if>
</where>
</sql>
<select id="findUserByUserNameAndSex" parameterType="cn.itheima.pojo.User" resultType="cn.itheima.pojo.User">
select * from user
<!-- 调用sql条件 -->
<include refid="user_Where"></include>
</select>
Foreach
public class QueryVo {
private User user;
private List<Integer> ids;
<select id="findUserByIds" parameterType="cn.itheima.pojo.QueryVo" resultType="cn.itheima.pojo.User">
select * from user
select * from user
<where>
<if test="ids != null">
<!--
foreach:循环传入的集合参数
collection:传入的集合的变量名称
item:每次循环将循环出的数据放入这个变量中
open:循环开始拼接的字符串
close:循环结束拼接的字符串
separator:循环中拼接的分隔符
-->
<foreach collection="ids" item="id" open="id in (" close=")" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
public void testFindUserbyIds() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
QueryVo vo = new QueryVo();
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(16);
ids.add(28);
ids.add(22);
vo.setIds(ids);
List<User> list = mapper.findUserByIds(vo);
System.out.println(list);
}
010.单个对象映射关系
一对一自动映射(少用)
public class CustomOrders extends Orders{
private int uid;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
}
//================================================
<!-- 一对一:自动映射 -->
<select id="findOrdersAndUser1" resultType="cn.itheima.pojo.CustomOrders">
select a.*, b.id uid, username, birthday, sex, address
from orders a, user b
where a.user_id = b.id
</select>
一对一手动映射
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
private User user;
<!-- 一对一:手动映射 -->
<!--
id:resultMap的唯一标识
type:将查询出的数据放入这个指定的对象中
注意:手动映射需要指定数据库中表的字段名与java中pojo类的属性名称的对应关系
-->
<resultMap type="cn.itheima.pojo.Orders" id="orderAndUserResultMap">
<!-- id标签指定主键字段对应关系
column:列,数据库中的字段名称
property:属性,java中pojo中的属性名称
-->
<id column="id" property="id"/>
<!-- result:标签指定非主键字段的对应关系 -->
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 这个标签指定单个对象的对应关系
property:指定将数据放入Orders中的user属性中
javaType:user属性的类型
-->
<association property="user" javaType="cn.itheima.pojo.User">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findOrdersAndUser2" resultMap="orderAndUserResultMap">
select a.*, b.id uid, username, birthday, sex, address
from orders a, user b
where a.user_id = b.id
</select>
@Test
public void testFindOrdersAnduUser2() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
List<Orders> list = mapper.findOrdersAndUser2();
System.out.println(list);
}
011.集合对象映射
public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
private List<Orders> ordersList;
<resultMap type="cn.itheima.pojo.User" id="userAndOrdersResultMap">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 指定对应的集合对象关系映射
property:将数据放入User对象中的ordersList属性中
ofType:指定ordersList属性的泛型类型
-->
<collection property="ordersList" ofType="cn.itheima.pojo.Orders">
<id column="oid" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
</collection>
</resultMap>
<select id="findUserAndOrders" resultMap="userAndOrdersResultMap">
select a.*, b.id oid ,user_id, number, createtime
from user a, orders b where a.id = b.user_id
</select>
public void testFindUserAndOrders() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
List<User> list = mapper.findUserAndOrders();
System.out.println(list);
}
012.spring和mybatis原生dao整合
applicationContext.xml
:将回话工厂放在spring中配置
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!-- 整合Sql会话工厂归spring管理 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis核心配置文件 -->
<property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
<!-- 指定会话工厂使用的数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--
配置原生Dao实现
注意:class必须指定Dao实现类的全路径名称
-->
<bean id="userDao" class="cn.itheima.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
Dao层处理:
注意需要继承SqlSessionDaoSupport,可以用于获取会化工厂从而得到连接
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User findUserById(Integer id) {
//sqlSesion是线程不安全的,所以它的最佳使用范围在方法体内
SqlSession openSession = this.getSqlSession();
User user = openSession.selectOne("test.findUserById", id);
//整合后会话归spring管理,所以不需要手动关闭.
//openSession.close();
return user;
}
@Override
public List<User> findUserByUserName(String userName) {
SqlSession openSession = this.getSqlSession();
List<User> list = openSession.selectList("test.findUserByUserName", userName);
return list;
}
}
测试类:
public class UserDaoTest {
private ApplicationContext applicatonContext;
@Before
public void setUp() throws Exception{
String configLocation = "classpath:ApplicationContext.xml";
applicatonContext = new ClassPathXmlApplicationContext(configLocation);
}
@Test
public void testFindUserById() throws Exception{
//获取UserDao对象, getBean中的字符串是在ApplicationContext.xml中声明的
UserDao userDao = (UserDao)applicatonContext.getBean("userDao");
User user = userDao.findUserById(1);
System.out.println(user);
}
}
013.spring和mybatis的mapper整合
applicationContext.xml
<!-- Mapper接口代理实现 -->
<!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> -->
<!-- 配置mapper接口的全路径名称 -->
<!-- <property name="mapperInterface" value="cn.itheima.mapper.UserMapper"></property> -->
<!-- <property name="sqlSessionFactory" ref="sqlSessionFactory"></property> -->
<!-- </bean> -->
<!-- 使用包扫描的方式批量引入Mapper
扫描后引用的时候可以使用类名,首字母小写.
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定要扫描的包的全路径名称,如果有多个包用英文状态下的逗号分隔 -->
<property name="basePackage" value="cn.itheima.mapper"></property>
</bean>
注意:在SqlMapConfig.xml中就不需要引入mapper配置文件了
测试
public class UserMapperTest {
private ApplicationContext applicatonContext;
@Before
public void setUp() throws Exception{
String configLocation = "classpath:ApplicationContext.xml";
applicatonContext = new ClassPathXmlApplicationContext(configLocation);
}
@Test
public void testFindUserById() throws Exception{
UserMapper userMapper = (UserMapper)applicatonContext.getBean("userMapper");
User user = userMapper.findUserById(1);
System.out.println(user);
}
}
014.逆向工程
01.搭建步骤
01.Mybatis核心包,连接数据库的包
02.创建generator.xml(不用记具体的,只要会改其中的一些内容即可)
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root"
password="admin">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection> -->
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="cn.itheima.pojo"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="cn.itheima.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.itheima.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<table tableName="orders"></table>
<table tableName="user"></table>
<!-- 有些表的字段需要指定java类型
<table schema="" tableName="">
<columnOverride column="" javaType="" />
</table> -->
</context>
</generatorConfiguration>
需要注意的点:数据库连接、生成mapper和pojo的位置、指定数据库表
03.运行方法
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class StartServer {
public void generator() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("genarator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
try {
StartServer startServer = new StartServer();
startServer.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:
逆向工程以后就会生成mapper配置文件里面会有可能执行的sql集合,直接拿过来用就好
逆向工程生成mapper文件里面的查询都是单表查询,如果想要多表查询,则在mapper配置文件最后再写即可。
015.逆向工程生成单表操作总结
public class UserMapperTest {
private ApplicationContext applicatonContext;
@Before
public void setUp() throws Exception{
String configLocation = "classpath:ApplicationContext.xml";
applicatonContext = new ClassPathXmlApplicationContext(configLocation);
}
}
01.根据主键ID查询
@Test
public void testFindUserById() throws Exception{
UserMapper userMapper = (UserMapper)applicatonContext.getBean("userMapper");
User user = userMapper.selectByPrimaryKey(1);
System.out.println(user);
}
02.根据性别和名称查询
@Test
public void testFindUserAndSex() throws Exception{
UserMapper userMapper = (UserMapper)applicatonContext.getBean("userMapper");
//创建UserExample对象
UserExample userExample = new UserExample();
//通过UserExample对象创建查询条件封装对象(Criteria中是封装的查询条件)
Criteria createCriteria = userExample.createCriteria();
//加入查询条件
createCriteria.andUsernameLike("%王%");
createCriteria.andSexEqualTo("1");
List<User> list = userMapper.selectByExample(userExample);
System.out.println(list);
}
/*
思路:
建立mapper对象userMapper-->
userMapper执行方法,alt+/出现selectByExample方法-->
selectByExample方法里面的参数是UserExample -->
建立UserExample 对象,并建立Criteria 对象,即参数对象-->
添加参数*/
转载于:https://blog.51cto.com/qinbin/2060221