1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
1.导入jar包
log4j日志包
mysql驱动包
mybatis的jar包
2.导入配置文件
log4j日志包
mybatis核心配置文件 xml
sql映射文件
3.编写代码
传统方式:
配置完核心配置文件后
直接在sql映射文件中编写sql语句
调用sqlSession的API,指定sql语句,执行方法
动态代理方式:
配置完核心配置文件后
在sql映射文件中编写sql语句
编写dao层的接口
调用sqlSession的getMapper方法,生成接口的实现类(代理类),
在代理类中调用Sqlsession的相关方法完成增删改查
API:
SqlSessionFactoryBuilder: 解析
作用: 解析配置文件(核心配置文件,sql映射文件)
方法: build(is);
SqlSessionFactory: 线程安全(内部没有共享的变量)
作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
方法: openSession(boolean);
SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
方法:
selectList("namespace.id",参数);
selectOne("namespace.id",参数);
insert("namespace.id",参数);
update("namespace.id",参数);
delete("namespace.id",参数);
rollback();
commit();
close();
T getMapper(T.class);
底层使用动态代理,生成接口的实现类,
在接口的实现类方法中调用以上方法完成增删改查
Mybatis
作用: 对jdbc进行了封装,将sql语句与java代码分离
一 传统方式实现Mybatis
程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)
入门实现
1.导入jar包
2.准备mybatis的配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
sql映射文件-user
<?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="user">
<!-- select 查询所有 -->
<select id="queryAll" resultType="user">
select * from user
</select>
<!-- select 一条记录 -->
<select id="queryOne" resultType="user" parameterType="int">
select * from user where id = #{id}
</select>
</mapper>
sql映射文件-product
<?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="product">
<!-- select 查询所有 -->
<select id="queryAll" resultType="product">
select * from product
</select>
</mapper>
启动解析过程
xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
String url;
String driver;
String username;
String password;
Map<String,Mapper>
key:String,存放当前sql的唯一标识
sql语句标签上id属性的值
命名空间.id
value: Mapper,当前的sql语句及返回值对象
Mapper.java 一个sql语句对应一个Mapper
String sql; // 配置文件中的sql语句
String resultType; // sql执行后返回的数据类型
String parameterType; // sql执行时需要传入的参数类型
3.编写自己的业务
mybatis提供的相关API方法
Mybatis封装好的方法:
SqlSession提供操作数据库的方法
参数1: mapperId = namespace.id; 找到对应的sql语句
参数2: 执行当前sql需要使用的参数
selectList("mapperId",参数...);
selectOne("mapperId",参数...);
insert("mapperId",参数...);
update("mapperId",参数...);
delete("mapperId",参数...);
在以上方法中封装了JDBC操作
commit();
rollback();
close();
创建接口的实现类对象(代理类)
getMapper(Class ...);
user业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
List<User> findAll() throws IOException;
User findById(int id);
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
/**
* 传统方式:
* 手动调用Mybatis提供的方法,完成增删改查
*/
public class UserMapperImpl implements UserMapper {
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<User> list = sqlSession.selectList("user.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
User user = sqlSession.selectOne("user.queryOne", id);
MybatisUtils.close(sqlSession);
return user;
}
/* private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("user.queryAll");
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.queryOne", id);
return user;
}*/
}
product业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
List<Product> findAll();
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
public class ProductMapperImpl implements ProductMapper {
@Override
public List<Product> findAll() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<Product> list = sqlSession.selectList("product.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
/*private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<Product> findAll() {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Product> list = sqlSession.selectList("product.queryAll");
sqlSession.close();
return list;
}*/
}
Mybatis工具类
package com.itheima.utils;
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.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession对象(默认手动提交事务)
* @return
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
/**
* 根据传递的参数,返回具体的sqlSession对象
* @param flag
* @return
*/
public static SqlSession getSqlSession(boolean flag){
return sqlSessionFactory.openSession(flag);
}
public static void close(SqlSession sqlSession){
if (sqlSession!=null){
sqlSession.close();
}
}
}
Log4j日志
1.导入jar包
2.导入配置文件
二 动态代理方式实现Mybatis★
程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行
约定大于配置:
框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定:
mybatis在定位sql语句时,使用的是 接口的全限定名.方法名称
例子: 查找findAll方法调用的sql语句
com.itheima.dao.UserDao.findAll
代码实现
1.导入jar包
2.编写配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
3.编写我们的逻辑
user接口
package com.itheima.dao;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper {
// 查询所有用户信息
List<User> findAll();
// 根据id查询
User findById(int id);
// 添加
int insertUser(User user);
int insertUser1(User user);
// 修改
int updateUser(Map<String,Object> userMap);
删除
int deleteUser(int id);
// 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
List<User> findUserByMohu(@Param("name") String username);
/**
* 将user表中的数据封装到对应的Person中
* @return
*/
List<Person> findUserToPerson();
/**
* 参数罗列时,必须给参数起别名
* @param username
* @param sex
* TODO: 请求参数有多个时,必须起别名
* @return
*/
List<User> findUserByTiaojian(@Param("username") String username,
@Param("sex") String sex);
/**
* 动态sql进行修改
* @return
*/
int updateUser1(User user);
/**
* 请求参数为数组
* @param ids
* @return
*/
List<User> findUserByIds1(int[] ids);
List<User> findUserByIds2(List<Integer> ids);
}
sql映射文件
<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
<!-- select 查询所有 -->
<select id="findAll" resultType="user">
select * from user
</select>
<!--
select标签: 表示查询,用于描述查询的sql语句
id: 唯一标识,找到唯一的一条sql语句
parameterType: 请求参数的类型
resultType: 返回值类型
返回值的全限定名(也可以使用别名)
TODO:获取请求参数: 在sql中获取请求携带的参数值
OGNL表达式: 获取请求携带的参数值
格式:
#{} : 占位符,底层使用PreparedStatement执行sql语句
${} : 字符串拼接,底层使用Statement执行sql语句
请求参数类型:
基本类型或String:
#{随便写}
${value}
pojo实体对象
#{属性名}
list
map
...
-->
<!--<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{随便写}
</select>-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = ${value}
</select>
<!--
增删改,默认返回int(影响的行数),此返回值不需要设置
OGNL: 获取pojo对象中的数据
#{属性名}
-->
<!--
resultType: 主键类型
keyColumn: 主键字段名称
keyProperty: 将查询结果赋给实体对象中的哪个属性
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
-->
<insert id="insertUser" parameterType="user">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
</insert>
<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 修改操作:
OGNL表达式: 获取map中的值
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user set username=#{username},birthday=#{birthday},
sex=#{sex},address=#{address} where id=#{id}
</update>
<!-- 删除 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!-- 模糊查询 -->
<select id="findUserByMohu" parameterType="string" resultType="user">
select * from user where username like concat("%",#{name},"%");
</select>
<!-- 别名查询,将查询结果封装到指定对象中 -->
<!--<select id="findUserToPerson" resultType="Person">
SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
</select>-->
<select id="findUserToPerson" resultMap="userToPersonMap">
SELECT * FROM user ;
</select>
<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
<resultMap id="userToPersonMap" type="Person">
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
select * from user
select * from user where username like concat('%',#{username},'%')
select * from user where sex = #{sex}
select * from user where username like concat('%',#{username},'%') and sex = #{sex}
-->
<select id="findUserByTiaojian" resultType="User">
select * from user
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<!-- 动态修改 -->
<update id="updateUser1" parameterType="User">
update user
<set>
<if test="username!=null and username!=''">
username=#{username},
</if>
<if test="birthday!=null and birthday!=''">
birthday=#{birthday},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
<if test="address!=null and address!=''">
address=#{address},
</if>
</set>
where id=#{id}
</update>
<!-- 遍历数组 -->
<select id="findUserByIds1" parameterType="int[]" resultType="user">
select * from user
<where>
id in
<foreach collection="array" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
<!-- 遍历list集合 -->
<select id="findUserByIds2" parameterType="list" resultType="user">
select * from user
<where>
id in
<foreach collection="list" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
</mapper>
测试代码
package com.itheima.test;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.*;
public class TestMybatis {
@Test
public void test01_FindAll(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findAll();
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test02_findById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = mapper.findById(5);
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 需求: 添加完毕后,获取最新添加的数据的id值
*/
@Test
public void test03_insertUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("托塔李天王1");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("陈塘关");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
@Test
public void test03_insertUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("嫦娥");
user.setSex("女");
user.setBirthday(new Date());
user.setAddress("月宫");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 修改
*/
@Test
public void test04_updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
Map<String, Object> map = new HashMap<>();
map.put("id",14);
map.put("username","玉皇大帝");
map.put("sex","男");
map.put("birthday",new Date());
map.put("address","天庭");
int i = mapper.updateUser(map);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test05_deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int i = mapper.deleteUser(10);
if(i>0){
System.out.println("删除成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test06_findUserByMohu(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByMohu("精");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test07_findUserToPerson(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Person> list = mapper.findUserToPerson();
for (Person person : list) {
System.out.println(person);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test08_findUserByTiaojian(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByTiaojian("精","女");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test09_updateUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setId(15);
user.setUsername("嫦娥");
user.setSex("男");
user.setAddress("月亮之上");
int i = mapper.updateUser1(user);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test10_findUserByIds1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int []arr = {1,3,4,5,6};
List<User> list = mapper.findUserByIds1(arr);
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test11_findUserByIds2(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(6);
List<User> list2 = mapper.findUserByIds2(list);
for (User user : list2) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
}
Mybatis核心API
SqlSessionFactoryBuilder:
1.解析核心配置文件,以及关联的sql映射文件
2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
1.封装了jdbc操作,增删改查
selectList("sql语句的id");
selectOne("...",参数);
insert("...");
update("...");
delete("...");
2.getMapper
生成dao接口的实现类对象(代理类)
3.事务控制的方法
commit();
rollback();
close();
sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
Conn conn;
// 第一个线程 : 1 张三
// 第二个线程 : 1 王五
public int update(String name ,int id ){
update 表名 set name = ? where id = ? ;
}
}
增删改查
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="com.itheima.pojo.User">
select * from user;
</select>
<!--
parameterType: 传入参数类型
可以传递的参数类型
基本数据类型 和 String
pojo对象
数组
list
map
编写格式:
以上类型的全限定名
基本数据类型 和 String: 直接编写类型名称: int _int
pojo对象: com.itheima.pojo.User
数组: _int[] int[]
list: list
map: map
ognl表达式:
#{变量名称}: 占位符
preparedStatement
pojo: 实体对象的属性名称
${变量名称}: 字符串拼接
Statement: 存在sql注入的风险
-->
<insert id="insertUser" parameterType="com.itheima.pojo.User">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 添加完成后,返回新增记录的id值
useGeneratedKeys: 开启获取主键自增的值 开关
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
-->
<insert id="insertUser1" parameterType="com.itheima.pojo.User"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<!-- 返回新增记录的id值
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
resultType: 返回值类型
order: 添加记录前或后
-->
<!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>-->
</insert>
<!-- 修改
出入参数: map
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user
set
username=#{username},
address=#{address},
sex=#{sex},
birthday=#{birthday}
where id = #{id}
</update>
<!-- 当传入参数为一个基本类型或String时,
#{随便写}
最好见名知意
-->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!--
如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
-->
<select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
<!-- select * from user where username like '%${name}%' -->
select * from user where username like concat('%',#{name},'%');
</select>
<!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
<select id="findUserToPerson" resultMap="findUserToPersonMap">
select * from user;
</select>
<!-- id: 当前resultMap的唯一标识
type: 将当前的一条查询结果封装的对象类型
-->
<resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
<!-- column: 数据库字段名称
property: 实体属性名称
-->
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
</mapper>
sql映射文件中的相关配置
作用: 主要用于编写sql语句
传入参数:
属性: parameterType
返回结果:
属性: resultType
属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
基本类型和String: 直接使用对应类型的类型名称即可
int long
pojo类型: 编写pojo的全限定名
全限定名= 包名+类名;
com.itheima.pojo.User
使用别名(别名需要在核心配置文件中进行配置)
map: map
list: list
数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
在idea中按两次 shift 键
TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
格式:
#{变量名称}: 占位符,preparedStatement
pojo: 实体对象的属性名称
map: 通过map的key获取value的值
基本类型或String:
#{随便定义} : 最好见名知意
list: 动态sql遍历
数组: 动态sql遍历
${变量名称}: 字符串拼接,Statement,存在sql注入的风险
基本类型或String:
${value} : 固定值
可以在参数列表中使用@Param("别名")给传入的参数起别名
动态sql
<!-- 抽取公共的sql语句 -->
<sql id="userSql">
select * from user
</sql>
<!-- 多条件查询 -->
<select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
<!-- 引用公共的sql语句 -->
<include refid="userSql"></include>
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<update id="updateUser1" parameterType="com.itheima.pojo.User">
update user
<set>
<if test="username!=null and username!='' ">
username=#{username},
</if>
<if test="address!=null and address!='' ">
address=#{address},
</if>
<if test="sex!=null and sex!='' ">
sex=#{sex},
</if>
<if test="birthday!=null">
birthday=#{birthday}
</if>
</set>
where id = #{id}
</update>
<select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
<select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
多表查询
一对一
-- 创建用户基本表 User实体
drop table if exists user;
-- 创建用户基本表
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
-- 用户描述信息表 UserInfo实体
create table user_info (
id int primary key, -- 既是主键又是外键
height double, -- 身高厘米
weight double, -- 体重公斤
married tinyint, -- 是否结婚,1为结婚,0为未婚
foreign key (id) references user(id)
);
-- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
-- ========================== java对象
User.java 封装用户的信息以及对应的描述信息
private id
private username
private birthday
private sex
private address
private UserInfo userInfo;
UserInfo.java 封装用户的描述信息,以及对应的用户信息
id
height
weight
married
User user;
多表查询的结果我们可以采用java的实体嵌套
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<select id="findUserAndUserInfo" resultMap="resultMap1">
SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对一的映射数据信息 -->
<association property="userInfo">
<id column="uiid" property="id"></id>
<result column="height" property="height"></result>
<result column="weight" property="weight"></result>
<result column="married" property="married"></result>
</association>
</resultMap>
</mapper>
一对多
-- 创建用户基本表 User实体
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
-- 创建订单表
create table orders(
oid int primary key auto_increment , -- 主键
user_id int not null, -- 用户id,外键
number varchar(20), -- 订单编号
create_time datetime, -- 下单时间
note varchar(100), -- 备注
foreign key(user_id) references user(id) -- 外键约束,关联主表的主键
);
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');
User.java 封装用户信息以及对应的订单信息
private id
private username
private birthday
private sex
private address
// 存放当前用户所拥有的多个订单
private List<Orders> ordersList;
Orders.java
oid
user_id
number
create_time
note
在一对多查询时,在一的一方提供多的一方的实体List集合
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<!-- 一对多查询 -->
<select id="findUserAndOrders" resultMap="resultMap1">
SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对多的映射关系 -->
<!--
property: 实体中对应属性的名称
javaType: 该属性对应的java的类型
ofType: 该属性对应的泛型类型
-->
<collection property="ordersList" javaType="list" ofType="orders">
<id column="oid" property="oid"></id>
<result column="user_id" property="user_id"></result>
<result column="number" property="number"></result>
<result column="create_time" property="create_time"></result>
<result column="note" property="note"></result>
</collection>
</resultMap>
</mapper>
多对多
-- 创建用户基本表 User实体
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
-- 角色
CREATE TABLE `role` (
role_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '角色id(主键)',
role_name VARCHAR(32) NOT NULL COMMENT '角色名称',
role_detail VARCHAR(100) DEFAULT NULL COMMENT '角色描述'
);
-- 插入角色记录
INSERT INTO role(role_name,role_detail) VALUES('校长','全校的管理者');
INSERT INTO role(role_name,role_detail) VALUES('讲师','传道授业解惑');
INSERT INTO role(role_name,role_detail) VALUES('班主任','班级的灵魂');
INSERT INTO role(role_name,role_detail) VALUES('助教','大家的朋友');
-- 中间表
CREATE TABLE user_role (
user_id INT NOT NULL COMMENT '用户id',
role_id INT NOT NULL COMMENT '角色id',
PRIMARY KEY (user_id,role_id), -- 复合主键
FOREIGN KEY (user_id) REFERENCES `user`(id),
FOREIGN KEY (role_id) REFERENCES role(role_id)
);
INSERT INTO user_role(user_id,role_id) VALUES(1,1); -- 1号用户对应1号角色
INSERT INTO user_role(user_id,role_id) VALUES(2,2);
INSERT INTO user_role(user_id,role_id) VALUES(6,2);
INSERT INTO user_role(user_id,role_id) VALUES(1,3);
INSERT INTO user_role(user_id,role_id) VALUES(2,1);
INSERT INTO user_role(user_id,role_id) VALUES(2,4);
-- ============================= 多对多
User.java 封装用户信息,以及用户对应的多个角色信息
private id
private username
private birthday
private sex
private address
private List<Role> roleList;
Role.java 封装角色信息,以及当前角色所属的多个用户信息
role_id
role_name
role_detail
List<User> userList;
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<!-- 一对多查询 -->
<select id="findUserAndRole" resultMap="resultMap1">
SELECT * FROM `user` u
LEFT JOIN user_role ur ON u.`id` = ur.`user_id`
LEFT JOIN role r ON ur.`role_id` = r.`role_id`;
</select>
<!-- 封装用户表的数据信息 -->
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</resultMap>
<resultMap id="resultMap1" type="user" extends="userResultMap">
<!-- 配置一对多的映射关系 -->
<!--
property: 实体中对应属性的名称
javaType: 该属性对应的java的类型
ofType: 该属性对应的泛型类型
-->
<collection property="roleList" javaType="list" ofType="role">
<id column="role_id" property="role_id"></id>
<result column="role_name" property="role_name"></result>
<result column="role_detail" property="role_detail"></result>
</collection>
</resultMap>
</mapper>
延迟加载(懒加载)
什么时候使用什么时候加载(查询)
一对一的延迟加载
# 查询所有用户信息以及对应的详细信息
select * from user u left join user_info ui on u.id = ui.id;
拆分
1.确定主表 user
查询主表的所有数据信息
select * from user;
2.根据关联条件,查询从表 userInfo
根据主表的id查询对应的详情
select * from user_info where id = #{id} ;
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
注意: 注意该标签编写的位置
<!-- 配置Mybatis的全局属性 -->
<settings>
<!-- 开启对懒加载的支持 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.配置懒加载
<!-- 查询所有用户信息 -->
<select id="findAll" resultMap="userResultMap">
select * from user;
</select>
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- property: 实体属性名称
select: 对应的sql语句所在的位置 id
column: 对应sql语句执行时的条件 -->
<association property="userInfo" select="findUserInofById" column="id"></association>
</resultMap>
<!-- 根据id查询用户详情 -->
<select id="findUserInofById" resultType="userinfo">
select * from user_info where id = #{id}
</select>
一对多的延迟加载
# 查询所有用户信息以及对应的订单详情
SELECT * FROM `user` u LEFT JOIN orders o ON u.`id`=o.`user_id` ;
拆分
1.确定主表 user
查询所有用户信息
select * from user;
2.根据关联条件,查询从表 orders
根据用户id查询当前用户拥有的订单
select * from orders where user_id = #{id}
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
注意: 注意该标签编写的位置
<!-- 配置Mybatis的全局属性 -->
<settings>
<!-- 开启对懒加载的支持 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.配置一对多延迟加载
<!-- 查询所有用户信息 -->
<select id="findAll" resultMap="userResultMap">
select * from user;
</select>
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对多的延迟加载 -->
<collection property="ordersList" javaType="list" ofType="orders"
select="findOrdersByUid" column="id"></collection>
</resultMap>
<!-- 根据用户id查询当前用户所拥有的订单 -->
<select id="findOrdersByUid" resultType="orders">
select * from orders where user_id = #{user_id}
</select>
三 注解方式实现Mybatis
将相关sql的配置到注解上,mybatis自动解析和加载
Mybatis常用注解:
注释: 对代码的解释说明,是给程序员看的
注解: 对代码的说明,是给jvm虚拟查看
作用: 可以代替配置文件
@Insert 添加
value属性: sql语句
@Options:可选配置(获取主键)
userGeneratedKeys:开关
keyProperty :对象属性
@Update:更新
Value:sql语句
@Delete : 删除
Value:sql语句
@Select : 查询
Value:sql语句
@SelectProvider : 拼接动态sql
配置查询结果和实体属性的映射关系:
@Results:声明映射关系的配置
Value:接受@Result的数组
@Result:
id: true(默认值为false)
property = "实体中的属性名"
column = "查询结果列名"
@Result:配置映射关系
Id:(boolean)声明是否为主键配置
Property:对象中的属性名
Column:查询的字段名
----------------------- 单表
查询所有用户信息
条件查询
模糊查询
聚合查询
添加用户信息
修改用户信息
删除用户信息
----------------------- 多表
一对一
一对多
注解的一对一映射
// 注意: 在Mybatis的核心配置文件中开启懒加载
延迟加载(懒加载)
// 查询所有用户信息
@Select("select * from user ;")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(
column = "id", // 懒加载需要传递的参数
property = "userInfo", // 懒加载的结果需要封装到哪个属性上
javaType = UserInfo.class, // 懒加载返回的结果的数据类型
one=@One(
// 懒加载时调用的sql语句的位置
select = "com.itheima.dao.UserDao.findUserInofById",
fetchType=FetchType.LAZY // 懒加载
)
)
})
List<User> findAll();
// 根据id查询用户详情
@Select("select * from user_info where id = #{id}")
UserInfo findUserInofById(int id);
注解的一对多映射
// 查询所有用户信息
@Select("select * from user ;")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(
column = "id", // 传递给延迟加载方法的参数
property = "ordersList", // 延迟加载结果封装的属性名称
javaType = List.class, // 属性的类型
many = @Many(
// 延迟加载sql语句的位置
select = "com.itheima.dao.UserDao.findOrdersByUid",
fetchType = FetchType.LAZY // 设置延迟加载
)
)
})
List<User> findAll();
// 根据用户id查询当前用户所拥有的订单信息
@Select("select * from orders where user_id = #{user_id}")
List<Orders> findOrdersByUid(int user_id);
Mybatis中的缓存(了解)
缓存: 临时存放,将数据临时存放到内存中,当程序停止后,内存就会被释放
作用: 降低数据库的压力
Mybatis的缓存:
一级缓存: sqlSession级别的缓存,是Mybatis自带的,关不掉,必须使用
二级缓存: 可以理解为是SqlSessionFactory基本的缓存,多个SQLSession之间可以共享
1.在Mybatis的核心配置文件中开启对二级缓存的支持
<setting name="cacheEnabled" value="true"/>
2.需要缓存的实体对象必须实现序列化接口
3.在sql映射文件中开启缓存支持
<!-- 开启对二级缓存的支持 -->
<cache/>
<!-- 查询所有用户信息 -->
<select id="findUserById" resultType="USer" useCache="true">
select * from user where id = #{id};
</select>
4.sqlSession提交和关闭
总结
Mybatis框架:
持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
Mybatis结构:
两类配置文件:
核心配置文件:
存放连接数据库的数据信息
1.设置加载的properties配置文件(获取连接数据库的基本信息)
2.设置别名(给类的全限定名起别名)
3.设置操作数据库时使用JDBC的事务,和连接池
4.设置sql映射文件的位置
sql映射文件:
存放sql语句
namespace: 用于区分多个sql映射文件
id: sql语句的唯一标识.
<select></select>
<insert></insert>
<delete></delete>
<update></update>
编写自己的业务代码:
传统方式:
在dao层编写业务接口,提供相关方法
编写接口的实现类,手动调用Mybatis提供的相关API
动态代理方式:
在dao层编写业务接口,提供相关方法
程序启动时:
程序启动时,优先解析所有的配置文件,将解析到的数据存放到Configuration对象中
Configuration对象:
别名配置
连接数据库的基本信息: url driver username password
Map<key,value>
key: namespace.id
value: MappedStatement
sql: sql语句
parameterType: 请求参数类型
resultType: 返回结果类型
...
API:
SqlSessionFactoryBuilder:负责解析配置文件
SqlSessionFactory: 线程安全的对象
负责创建SqlSession对象并将解析到的Configuration传递给SqlSession
SqlSession: 不是线程安全的对象
提供了操作数据库的相关方法,在相关方法中封装了JDBC操作完成增删改查
selectList(参数1,参数2);
selectOne(参数1,参数2);
insert(参数1,参数2);
update(参数1,参数2);
delete(参数1,参数2);
commit();
rollback();
close();
T getMapper(T.class);
传统方式: 了解
动态代理方式: ★★★
导入jar包
导入核心配置文件(log4j配置文件)
编写user业务的接口,提供相关方法
在user业务对应的sql映射文件中编写sql语句
namespace: 接口的全限定名
id: 接口中的方法名称
------------------------------------------------
核心配置文件:
1.设置加载的properties配置文件(获取连接数据库的基本信息)
2.设置别名(给类的全限定名起别名)
3.设置操作数据库时使用JDBC的事务,和连接池
4.设置sql映射文件的位置
Sql映射文件:
<select></select>
<insert></insert>
<delete></delete>
<update></update>
传入参数类型:
基本类型和String:
直接写对应类型的名称即可
pojo对象:
全限定名
别名
map: map
list: list
数组: int[] _int[]
获取传入参数的值:
OGNL表达式:获取传入参数的值
格式:
#{} 占位符,preparedStatement对象
${} 拼接符,Statement对象
基本类型和String:
#{随便写} ${value}
pojo对象:
#{pojo对象中的属性名}
${pojo对象中的属性名}
map: map
#{map的key}
${map的key}
list: list
遍历
数组: int[] _int[]
遍历
传出参数类型:
基本类型和String:
直接写对应类型的名称即可
pojo对象:
全限定名
别名
list<泛型>:
使用泛型类型的全限定名或别名(将一条记录封装到哪个对象中)
回顾
1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
1.导入jar包
log4j日志包
mysql驱动包
mybatis的jar包
2.导入配置文件
log4j日志包
mybatis核心配置文件 xml
sql映射文件
3.编写代码
传统方式:
配置完核心配置文件后
直接在sql映射文件中编写sql语句
调用sqlSession的API,指定sql语句,执行方法
动态代理方式:
配置完核心配置文件后
在sql映射文件中编写sql语句
编写dao层的接口
调用sqlSession的getMapper方法,生成接口的实现类(代理类),
在代理类中调用Sqlsession的相关方法完成增删改查
API:
SqlSessionFactoryBuilder: 解析
作用: 解析配置文件(核心配置文件,sql映射文件)
方法: build(is);
SqlSessionFactory: 线程安全(内部没有共享的变量)
作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
方法: openSession(boolean);
SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
方法:
selectList("namespace.id",参数);
selectOne("namespace.id",参数);
insert("namespace.id",参数);
update("namespace.id",参数);
delete("namespace.id",参数);
rollback();
commit();
close();
T getMapper(T.class);
底层使用动态代理,生成接口的实现类,
在接口的实现类方法中调用以上方法完成增删改查
Mybatis
作用: 对jdbc进行了封装,将sql语句与java代码分离
一 传统方式实现Mybatis
程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)
入门实现
1.导入jar包
2.准备mybatis的配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
sql映射文件-user
<?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="user">
<!-- select 查询所有 -->
<select id="queryAll" resultType="user">
select * from user
</select>
<!-- select 一条记录 -->
<select id="queryOne" resultType="user" parameterType="int">
select * from user where id = #{id}
</select>
</mapper>
sql映射文件-product
<?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="product">
<!-- select 查询所有 -->
<select id="queryAll" resultType="product">
select * from product
</select>
</mapper>
启动解析过程
xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
String url;
String driver;
String username;
String password;
Map<String,Mapper>
key:String,存放当前sql的唯一标识
sql语句标签上id属性的值
命名空间.id
value: Mapper,当前的sql语句及返回值对象
Mapper.java 一个sql语句对应一个Mapper
String sql; // 配置文件中的sql语句
String resultType; // sql执行后返回的数据类型
String parameterType; // sql执行时需要传入的参数类型
3.编写自己的业务
mybatis提供的相关API方法
Mybatis封装好的方法:
SqlSession提供操作数据库的方法
参数1: mapperId = namespace.id; 找到对应的sql语句
参数2: 执行当前sql需要使用的参数
selectList("mapperId",参数...);
selectOne("mapperId",参数...);
insert("mapperId",参数...);
update("mapperId",参数...);
delete("mapperId",参数...);
在以上方法中封装了JDBC操作
commit();
rollback();
close();
创建接口的实现类对象(代理类)
getMapper(Class ...);
user业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
List<User> findAll() throws IOException;
User findById(int id);
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
/**
* 传统方式:
* 手动调用Mybatis提供的方法,完成增删改查
*/
public class UserMapperImpl implements UserMapper {
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<User> list = sqlSession.selectList("user.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
User user = sqlSession.selectOne("user.queryOne", id);
MybatisUtils.close(sqlSession);
return user;
}
/* private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("user.queryAll");
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.queryOne", id);
return user;
}*/
}
product业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
List<Product> findAll();
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
public class ProductMapperImpl implements ProductMapper {
@Override
public List<Product> findAll() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<Product> list = sqlSession.selectList("product.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
/*private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<Product> findAll() {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Product> list = sqlSession.selectList("product.queryAll");
sqlSession.close();
return list;
}*/
}
Mybatis工具类
package com.itheima.utils;
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.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession对象(默认手动提交事务)
* @return
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
/**
* 根据传递的参数,返回具体的sqlSession对象
* @param flag
* @return
*/
public static SqlSession getSqlSession(boolean flag){
return sqlSessionFactory.openSession(flag);
}
public static void close(SqlSession sqlSession){
if (sqlSession!=null){
sqlSession.close();
}
}
}
Log4j日志
1.导入jar包
2.导入配置文件
二 动态代理方式实现Mybatis★
程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行
约定大于配置:
框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定:
mybatis在定位sql语句时,使用的是 接口的全限定名.方法名称
例子: 查找findAll方法调用的sql语句
com.itheima.dao.UserDao.findAll
代码实现
1.导入jar包
2.编写配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
3.编写我们的逻辑
user接口
package com.itheima.dao;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper {
// 查询所有用户信息
List<User> findAll();
// 根据id查询
User findById(int id);
// 添加
int insertUser(User user);
int insertUser1(User user);
// 修改
int updateUser(Map<String,Object> userMap);
删除
int deleteUser(int id);
// 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
List<User> findUserByMohu(@Param("name") String username);
/**
* 将user表中的数据封装到对应的Person中
* @return
*/
List<Person> findUserToPerson();
/**
* 参数罗列时,必须给参数起别名
* @param username
* @param sex
* TODO: 请求参数有多个时,必须起别名
* @return
*/
List<User> findUserByTiaojian(@Param("username") String username,
@Param("sex") String sex);
/**
* 动态sql进行修改
* @return
*/
int updateUser1(User user);
/**
* 请求参数为数组
* @param ids
* @return
*/
List<User> findUserByIds1(int[] ids);
List<User> findUserByIds2(List<Integer> ids);
}
sql映射文件
<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
<!-- select 查询所有 -->
<select id="findAll" resultType="user">
select * from user
</select>
<!--
select标签: 表示查询,用于描述查询的sql语句
id: 唯一标识,找到唯一的一条sql语句
parameterType: 请求参数的类型
resultType: 返回值类型
返回值的全限定名(也可以使用别名)
TODO:获取请求参数: 在sql中获取请求携带的参数值
OGNL表达式: 获取请求携带的参数值
格式:
#{} : 占位符,底层使用PreparedStatement执行sql语句
${} : 字符串拼接,底层使用Statement执行sql语句
请求参数类型:
基本类型或String:
#{随便写}
${value}
pojo实体对象
#{属性名}
list
map
...
-->
<!--<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{随便写}
</select>-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = ${value}
</select>
<!--
增删改,默认返回int(影响的行数),此返回值不需要设置
OGNL: 获取pojo对象中的数据
#{属性名}
-->
<!--
resultType: 主键类型
keyColumn: 主键字段名称
keyProperty: 将查询结果赋给实体对象中的哪个属性
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
-->
<insert id="insertUser" parameterType="user">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
</insert>
<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 修改操作:
OGNL表达式: 获取map中的值
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user set username=#{username},birthday=#{birthday},
sex=#{sex},address=#{address} where id=#{id}
</update>
<!-- 删除 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!-- 模糊查询 -->
<select id="findUserByMohu" parameterType="string" resultType="user">
select * from user where username like concat("%",#{name},"%");
</select>
<!-- 别名查询,将查询结果封装到指定对象中 -->
<!--<select id="findUserToPerson" resultType="Person">
SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
</select>-->
<select id="findUserToPerson" resultMap="userToPersonMap">
SELECT * FROM user ;
</select>
<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
<resultMap id="userToPersonMap" type="Person">
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
select * from user
select * from user where username like concat('%',#{username},'%')
select * from user where sex = #{sex}
select * from user where username like concat('%',#{username},'%') and sex = #{sex}
-->
<select id="findUserByTiaojian" resultType="User">
select * from user
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<!-- 动态修改 -->
<update id="updateUser1" parameterType="User">
update user
<set>
<if test="username!=null and username!=''">
username=#{username},
</if>
<if test="birthday!=null and birthday!=''">
birthday=#{birthday},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
<if test="address!=null and address!=''">
address=#{address},
</if>
</set>
where id=#{id}
</update>
<!-- 遍历数组 -->
<select id="findUserByIds1" parameterType="int[]" resultType="user">
select * from user
<where>
id in
<foreach collection="array" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
<!-- 遍历list集合 -->
<select id="findUserByIds2" parameterType="list" resultType="user">
select * from user
<where>
id in
<foreach collection="list" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
</mapper>
测试代码
package com.itheima.test;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.*;
public class TestMybatis {
@Test
public void test01_FindAll(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findAll();
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test02_findById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = mapper.findById(5);
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 需求: 添加完毕后,获取最新添加的数据的id值
*/
@Test
public void test03_insertUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("托塔李天王1");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("陈塘关");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
@Test
public void test03_insertUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("嫦娥");
user.setSex("女");
user.setBirthday(new Date());
user.setAddress("月宫");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 修改
*/
@Test
public void test04_updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
Map<String, Object> map = new HashMap<>();
map.put("id",14);
map.put("username","玉皇大帝");
map.put("sex","男");
map.put("birthday",new Date());
map.put("address","天庭");
int i = mapper.updateUser(map);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test05_deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int i = mapper.deleteUser(10);
if(i>0){
System.out.println("删除成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test06_findUserByMohu(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByMohu("精");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test07_findUserToPerson(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Person> list = mapper.findUserToPerson();
for (Person person : list) {
System.out.println(person);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test08_findUserByTiaojian(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByTiaojian("精","女");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test09_updateUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setId(15);
user.setUsername("嫦娥");
user.setSex("男");
user.setAddress("月亮之上");
int i = mapper.updateUser1(user);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test10_findUserByIds1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int []arr = {1,3,4,5,6};
List<User> list = mapper.findUserByIds1(arr);
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test11_findUserByIds2(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(6);
List<User> list2 = mapper.findUserByIds2(list);
for (User user : list2) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
}
Mybatis核心API
SqlSessionFactoryBuilder:
1.解析核心配置文件,以及关联的sql映射文件
2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
1.封装了jdbc操作,增删改查
selectList("sql语句的id");
selectOne("...",参数);
insert("...");
update("...");
delete("...");
2.getMapper
生成dao接口的实现类对象(代理类)
3.事务控制的方法
commit();
rollback();
close();
sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
Conn conn;
// 第一个线程 : 1 张三
// 第二个线程 : 1 王五
public int update(String name ,int id ){
update 表名 set name = ? where id = ? ;
}
}
增删改查
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="com.itheima.pojo.User">
select * from user;
</select>
<!--
parameterType: 传入参数类型
可以传递的参数类型
基本数据类型 和 String
pojo对象
数组
list
map
编写格式:
以上类型的全限定名
基本数据类型 和 String: 直接编写类型名称: int _int
pojo对象: com.itheima.pojo.User
数组: _int[] int[]
list: list
map: map
ognl表达式:
#{变量名称}: 占位符
preparedStatement
pojo: 实体对象的属性名称
${变量名称}: 字符串拼接
Statement: 存在sql注入的风险
-->
<insert id="insertUser" parameterType="com.itheima.pojo.User">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 添加完成后,返回新增记录的id值
useGeneratedKeys: 开启获取主键自增的值 开关
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
-->
<insert id="insertUser1" parameterType="com.itheima.pojo.User"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<!-- 返回新增记录的id值
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
resultType: 返回值类型
order: 添加记录前或后
-->
<!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>-->
</insert>
<!-- 修改
出入参数: map
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user
set
username=#{username},
address=#{address},
sex=#{sex},
birthday=#{birthday}
where id = #{id}
</update>
<!-- 当传入参数为一个基本类型或String时,
#{随便写}
最好见名知意
-->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!--
如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
-->
<select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
<!-- select * from user where username like '%${name}%' -->
select * from user where username like concat('%',#{name},'%');
</select>
<!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
<select id="findUserToPerson" resultMap="findUserToPersonMap">
select * from user;
</select>
<!-- id: 当前resultMap的唯一标识
type: 将当前的一条查询结果封装的对象类型
-->
<resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
<!-- column: 数据库字段名称
property: 实体属性名称
-->
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
</mapper>
sql映射文件中的相关配置
作用: 主要用于编写sql语句
传入参数:
属性: parameterType
返回结果:
属性: resultType
属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
基本类型和String: 直接使用对应类型的类型名称即可
int long
pojo类型: 编写pojo的全限定名
全限定名= 包名+类名;
com.itheima.pojo.User
使用别名(别名需要在核心配置文件中进行配置)
map: map
list: list
数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
在idea中按两次 shift 键
TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
格式:
#{变量名称}: 占位符,preparedStatement
pojo: 实体对象的属性名称
map: 通过map的key获取value的值
基本类型或String:
#{随便定义} : 最好见名知意
list: 动态sql遍历
数组: 动态sql遍历
${变量名称}: 字符串拼接,Statement,存在sql注入的风险
基本类型或String:
${value} : 固定值
可以在参数列表中使用@Param("别名")给传入的参数起别名
动态sql
<!-- 抽取公共的sql语句 -->
<sql id="userSql">
select * from user
</sql>
<!-- 多条件查询 -->
<select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
<!-- 引用公共的sql语句 -->
<include refid="userSql"></include>
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<update id="updateUser1" parameterType="com.itheima.pojo.User">
update user
<set>
<if test="username!=null and username!='' ">
username=#{username},
</if>
<if test="address!=null and address!='' ">
address=#{address},
</if>
<if test="sex!=null and sex!='' ">
sex=#{sex},
</if>
<if test="birthday!=null">
birthday=#{birthday}
</if>
</set>
where id = #{id}
</update>
<select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
<select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
多表查询
一对一
-- 创建用户基本表 User实体
drop table if exists user;
-- 创建用户基本表
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
-- 用户描述信息表 UserInfo实体
create table user_info (
id int primary key, -- 既是主键又是外键
height double, -- 身高厘米
weight double, -- 体重公斤
married tinyint, -- 是否结婚,1为结婚,0为未婚
foreign key (id) references user(id)
);
-- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
-- ========================== java对象
User.java 封装用户的信息以及对应的描述信息
private id
private username
private birthday
private sex
private address
private UserInfo userInfo;
UserInfo.java 封装用户的描述信息,以及对应的用户信息
id
height
weight
married
User user;
多表查询的结果我们可以采用java的实体嵌套
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<select id="findUserAndUserInfo" resultMap="resultMap1">
SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对一的映射数据信息 -->
<association property="userInfo">
<id column="uiid" property="id"></id>
<result column="height" property="height"></result>
<result column="weight" property="weight"></result>
<result column="married" property="married"></result>
</association>
</resultMap>
</mapper>
一对多
-- 创建用户基本表 User实体
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
-- 创建订单表
create table orders(
oid int primary key auto_increment , -- 主键
user_id int not null, -- 用户id,外键
number varchar(20), -- 订单编号
create_time datetime, -- 下单时间
note varchar(100), -- 备注
foreign key(user_id) references user(id) -- 外键约束,关联主表的主键
);
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');
User.java 封装用户信息以及对应的订单信息
private id
private username
private birthday
private sex
private address
// 存放当前用户所拥有的多个订单
private List<Orders> ordersList;
Orders.java
oid
user_id
number
create_time
note
在一对多查询时,在一的一方提供多的一方的实体List集合
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<!-- 一对多查询 -->
<select id="findUserAndOrders" resultMap="resultMap1">
SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对多的映射关系 -->
<!--
property: 实体中对应属性的名称
javaType: 该属性对应的java的类型
ofType: 该属性对应的泛型类型
-->
<collection property="ordersList" javaType="list" ofType="orders">
<id column="oid" property="oid"></id>
<result column="user_id" property="user_id"></result>
<result column="number" property="number"></result>
<result column="create_time" property="create_time"></result>
<result column="note" property="note"></result>
</collection>
</resultMap>
</mapper>
多对多
-- 创建用户基本表 User实体
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
-- 角色
CREATE TABLE `role` (
role_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '角色id(主键)',
role_name VARCHAR(32) NOT NULL COMMENT '角色名称',
role_detail VARCHAR(100) DEFAULT NULL COMMENT '角色描述'
);
-- 插入角色记录
INSERT INTO role(role_name,role_detail) VALUES('校长','全校的管理者');
INSERT INTO role(role_name,role_detail) VALUES('讲师','传道授业解惑');
INSERT INTO role(role_name,role_detail) VALUES('班主任','班级的灵魂');
INSERT INTO role(role_name,role_detail) VALUES('助教','大家的朋友');
-- 中间表
CREATE TABLE user_role (
user_id INT NOT NULL COMMENT '用户id',
role_id INT NOT NULL COMMENT '角色id',
PRIMARY KEY (user_id,role_id), -- 复合主键
FOREIGN KEY (user_id) REFERENCES `user`(id),
FOREIGN KEY (role_id) REFERENCES role(role_id)
);
INSERT INTO user_role(user_id,role_id) VALUES(1,1); -- 1号用户对应1号角色
INSERT INTO user_role(user_id,role_id) VALUES(2,2);
INSERT INTO user_role(user_id,role_id) VALUES(6,2);
INSERT INTO user_role(user_id,role_id) VALUES(1,3);
INSERT INTO user_role(user_id,role_id) VALUES(2,1);
INSERT INTO user_role(user_id,role_id) VALUES(2,4);
-- ============================= 多对多
User.java 封装用户信息,以及用户对应的多个角色信息
private id
private username
private birthday
private sex
private address
private List<Role> roleList;
Role.java 封装角色信息,以及当前角色所属的多个用户信息
role_id
role_name
role_detail
List<User> userList;
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<!-- 一对多查询 -->
<select id="findUserAndRole" resultMap="resultMap1">
SELECT * FROM `user` u
LEFT JOIN user_role ur ON u.`id` = ur.`user_id`
LEFT JOIN role r ON ur.`role_id` = r.`role_id`;
</select>
<!-- 封装用户表的数据信息 -->
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</resultMap>
<resultMap id="resultMap1" type="user" extends="userResultMap">
<!-- 配置一对多的映射关系 -->
<!--
property: 实体中对应属性的名称
javaType: 该属性对应的java的类型
ofType: 该属性对应的泛型类型
-->
<collection property="roleList" javaType="list" ofType="role">
<id column="role_id" property="role_id"></id>
<result column="role_name" property="role_name"></result>
<result column="role_detail" property="role_detail"></result>
</collection>
</resultMap>
</mapper>
延迟加载(懒加载)
什么时候使用什么时候加载(查询)
一对一的延迟加载
# 查询所有用户信息以及对应的详细信息
select * from user u left join user_info ui on u.id = ui.id;
拆分
1.确定主表 user
查询主表的所有数据信息
select * from user;
2.根据关联条件,查询从表 userInfo
根据主表的id查询对应的详情
select * from user_info where id = #{id} ;
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
注意: 注意该标签编写的位置
<!-- 配置Mybatis的全局属性 -->
<settings>
<!-- 开启对懒加载的支持 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.配置懒加载
<!-- 查询所有用户信息 -->
<select id="findAll" resultMap="userResultMap">
select * from user;
</select>
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- property: 实体属性名称
select: 对应的sql语句所在的位置 id
column: 对应sql语句执行时的条件 -->
<association property="userInfo" select="findUserInofById" column="id"></association>
</resultMap>
<!-- 根据id查询用户详情 -->
<select id="findUserInofById" resultType="userinfo">
select * from user_info where id = #{id}
</select>
一对多的延迟加载
# 查询所有用户信息以及对应的订单详情
SELECT * FROM `user` u LEFT JOIN orders o ON u.`id`=o.`user_id` ;
拆分
1.确定主表 user
查询所有用户信息
select * from user;
2.根据关联条件,查询从表 orders
根据用户id查询当前用户拥有的订单
select * from orders where user_id = #{id}
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
注意: 注意该标签编写的位置
<!-- 配置Mybatis的全局属性 -->
<settings>
<!-- 开启对懒加载的支持 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.配置一对多延迟加载
<!-- 查询所有用户信息 -->
<select id="findAll" resultMap="userResultMap">
select * from user;
</select>
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对多的延迟加载 -->
<collection property="ordersList" javaType="list" ofType="orders"
select="findOrdersByUid" column="id"></collection>
</resultMap>
<!-- 根据用户id查询当前用户所拥有的订单 -->
<select id="findOrdersByUid" resultType="orders">
select * from orders where user_id = #{user_id}
</select>
三 注解方式实现Mybatis
将相关sql的配置到注解上,mybatis自动解析和加载
Mybatis常用注解:
注释: 对代码的解释说明,是给程序员看的
注解: 对代码的说明,是给jvm虚拟查看
作用: 可以代替配置文件
@Insert 添加
value属性: sql语句
@Options:可选配置(获取主键)
userGeneratedKeys:开关
keyProperty :对象属性
@Update:更新
Value:sql语句
@Delete : 删除
Value:sql语句
@Select : 查询
Value:sql语句
@SelectProvider : 拼接动态sql
配置查询结果和实体属性的映射关系:
@Results:声明映射关系的配置
Value:接受@Result的数组
@Result:
id: true(默认值为false)
property = "实体中的属性名"
column = "查询结果列名"
@Result:配置映射关系
Id:(boolean)声明是否为主键配置
Property:对象中的属性名
Column:查询的字段名
----------------------- 单表
查询所有用户信息
条件查询
模糊查询
聚合查询
添加用户信息
修改用户信息
删除用户信息
----------------------- 多表
一对一
一对多
注解的一对一映射
// 注意: 在Mybatis的核心配置文件中开启懒加载
延迟加载(懒加载)
// 查询所有用户信息
@Select("select * from user ;")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(
column = "id", // 懒加载需要传递的参数
property = "userInfo", // 懒加载的结果需要封装到哪个属性上
javaType = UserInfo.class, // 懒加载返回的结果的数据类型
one=@One(
// 懒加载时调用的sql语句的位置
select = "com.itheima.dao.UserDao.findUserInofById",
fetchType=FetchType.LAZY // 懒加载
)
)
})
List<User> findAll();
// 根据id查询用户详情
@Select("select * from user_info where id = #{id}")
UserInfo findUserInofById(int id);
注解的一对多映射
// 查询所有用户信息
@Select("select * from user ;")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(
column = "id", // 传递给延迟加载方法的参数
property = "ordersList", // 延迟加载结果封装的属性名称
javaType = List.class, // 属性的类型
many = @Many(
// 延迟加载sql语句的位置
select = "com.itheima.dao.UserDao.findOrdersByUid",
fetchType = FetchType.LAZY // 设置延迟加载
)
)
})
List<User> findAll();
// 根据用户id查询当前用户所拥有的订单信息
@Select("select * from orders where user_id = #{user_id}")
List<Orders> findOrdersByUid(int user_id);
Mybatis中的缓存(了解)
缓存: 临时存放,将数据临时存放到内存中,当程序停止后,内存就会被释放
作用: 降低数据库的压力
Mybatis的缓存:
一级缓存: sqlSession级别的缓存,是Mybatis自带的,关不掉,必须使用
二级缓存: 可以理解为是SqlSessionFactory基本的缓存,多个SQLSession之间可以共享
1.在Mybatis的核心配置文件中开启对二级缓存的支持
<setting name="cacheEnabled" value="true"/>
2.需要缓存的实体对象必须实现序列化接口
3.在sql映射文件中开启缓存支持
<!-- 开启对二级缓存的支持 -->
<cache/>
<!-- 查询所有用户信息 -->
<select id="findUserById" resultType="USer" useCache="true">
select * from user where id = #{id};
</select>
4.sqlSession提交和关闭
总结
Mybatis框架:
持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
Mybatis结构:
两类配置文件:
核心配置文件:
存放连接数据库的数据信息
1.设置加载的properties配置文件(获取连接数据库的基本信息)
2.设置别名(给类的全限定名起别名)
3.设置操作数据库时使用JDBC的事务,和连接池
4.设置sql映射文件的位置
sql映射文件:
存放sql语句
namespace: 用于区分多个sql映射文件
id: sql语句的唯一标识.
<select></select>
<insert></insert>
<delete></delete>
<update></update>
编写自己的业务代码:
传统方式:
在dao层编写业务接口,提供相关方法
编写接口的实现类,手动调用Mybatis提供的相关API
动态代理方式:
在dao层编写业务接口,提供相关方法
程序启动时:
程序启动时,优先解析所有的配置文件,将解析到的数据存放到Configuration对象中
Configuration对象:
别名配置
连接数据库的基本信息: url driver username password
Map<key,value>
key: namespace.id
value: MappedStatement
sql: sql语句
parameterType: 请求参数类型
resultType: 返回结果类型
...
API:
SqlSessionFactoryBuilder:负责解析配置文件
SqlSessionFactory: 线程安全的对象
负责创建SqlSession对象并将解析到的Configuration传递给SqlSession
SqlSession: 不是线程安全的对象
提供了操作数据库的相关方法,在相关方法中封装了JDBC操作完成增删改查
selectList(参数1,参数2);
selectOne(参数1,参数2);
insert(参数1,参数2);
update(参数1,参数2);
delete(参数1,参数2);
commit();
rollback();
close();
T getMapper(T.class);
传统方式: 了解
动态代理方式: ★★★
导入jar包
导入核心配置文件(log4j配置文件)
编写user业务的接口,提供相关方法
在user业务对应的sql映射文件中编写sql语句
namespace: 接口的全限定名
id: 接口中的方法名称
------------------------------------------------
核心配置文件:
1.设置加载的properties配置文件(获取连接数据库的基本信息)
2.设置别名(给类的全限定名起别名)
3.设置操作数据库时使用JDBC的事务,和连接池
4.设置sql映射文件的位置
Sql映射文件:
<select></select>
<insert></insert>
<delete></delete>
<update></update>
传入参数类型:
基本类型和String:
直接写对应类型的名称即可
pojo对象:
全限定名
别名
map: map
list: list
数组: int[] _int[]
获取传入参数的值:
OGNL表达式:获取传入参数的值
格式:
#{} 占位符,preparedStatement对象
${} 拼接符,Statement对象
基本类型和String:
#{随便写} ${value}
pojo对象:
#{pojo对象中的属性名}
${pojo对象中的属性名}
map: map
#{map的key}
${map的key}
list: list
遍历
数组: int[] _int[]
遍历
传出参数类型:
基本类型和String:
直接写对应类型的名称即可
pojo对象:
全限定名
别名
list<泛型>:
使用泛型类型的全限定名或别名(将一条记录封装到哪个对象中)
回顾
1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
1.导入jar包
log4j日志包
mysql驱动包
mybatis的jar包
2.导入配置文件
log4j日志包
mybatis核心配置文件 xml
sql映射文件
3.编写代码
传统方式:
配置完核心配置文件后
直接在sql映射文件中编写sql语句
调用sqlSession的API,指定sql语句,执行方法
动态代理方式:
配置完核心配置文件后
在sql映射文件中编写sql语句
编写dao层的接口
调用sqlSession的getMapper方法,生成接口的实现类(代理类),
在代理类中调用Sqlsession的相关方法完成增删改查
API:
SqlSessionFactoryBuilder: 解析
作用: 解析配置文件(核心配置文件,sql映射文件)
方法: build(is);
SqlSessionFactory: 线程安全(内部没有共享的变量)
作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
方法: openSession(boolean);
SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
方法:
selectList("namespace.id",参数);
selectOne("namespace.id",参数);
insert("namespace.id",参数);
update("namespace.id",参数);
delete("namespace.id",参数);
rollback();
commit();
close();
T getMapper(T.class);
底层使用动态代理,生成接口的实现类,
在接口的实现类方法中调用以上方法完成增删改查
Mybatis
作用: 对jdbc进行了封装,将sql语句与java代码分离
一 传统方式实现Mybatis
程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)
入门实现
1.导入jar包
2.准备mybatis的配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
sql映射文件-user
<?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="user">
<!-- select 查询所有 -->
<select id="queryAll" resultType="user">
select * from user
</select>
<!-- select 一条记录 -->
<select id="queryOne" resultType="user" parameterType="int">
select * from user where id = #{id}
</select>
</mapper>
sql映射文件-product
<?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="product">
<!-- select 查询所有 -->
<select id="queryAll" resultType="product">
select * from product
</select>
</mapper>
启动解析过程
xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
String url;
String driver;
String username;
String password;
Map<String,Mapper>
key:String,存放当前sql的唯一标识
sql语句标签上id属性的值
命名空间.id
value: Mapper,当前的sql语句及返回值对象
Mapper.java 一个sql语句对应一个Mapper
String sql; // 配置文件中的sql语句
String resultType; // sql执行后返回的数据类型
String parameterType; // sql执行时需要传入的参数类型
3.编写自己的业务
mybatis提供的相关API方法
Mybatis封装好的方法:
SqlSession提供操作数据库的方法
参数1: mapperId = namespace.id; 找到对应的sql语句
参数2: 执行当前sql需要使用的参数
selectList("mapperId",参数...);
selectOne("mapperId",参数...);
insert("mapperId",参数...);
update("mapperId",参数...);
delete("mapperId",参数...);
在以上方法中封装了JDBC操作
commit();
rollback();
close();
创建接口的实现类对象(代理类)
getMapper(Class ...);
user业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
List<User> findAll() throws IOException;
User findById(int id);
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
/**
* 传统方式:
* 手动调用Mybatis提供的方法,完成增删改查
*/
public class UserMapperImpl implements UserMapper {
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<User> list = sqlSession.selectList("user.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
User user = sqlSession.selectOne("user.queryOne", id);
MybatisUtils.close(sqlSession);
return user;
}
/* private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("user.queryAll");
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.queryOne", id);
return user;
}*/
}
product业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
List<Product> findAll();
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
public class ProductMapperImpl implements ProductMapper {
@Override
public List<Product> findAll() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<Product> list = sqlSession.selectList("product.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
/*private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<Product> findAll() {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Product> list = sqlSession.selectList("product.queryAll");
sqlSession.close();
return list;
}*/
}
Mybatis工具类
package com.itheima.utils;
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.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession对象(默认手动提交事务)
* @return
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
/**
* 根据传递的参数,返回具体的sqlSession对象
* @param flag
* @return
*/
public static SqlSession getSqlSession(boolean flag){
return sqlSessionFactory.openSession(flag);
}
public static void close(SqlSession sqlSession){
if (sqlSession!=null){
sqlSession.close();
}
}
}
Log4j日志
1.导入jar包
2.导入配置文件
二 动态代理方式实现Mybatis★
程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行
约定大于配置:
框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定:
mybatis在定位sql语句时,使用的是 接口的全限定名.方法名称
例子: 查找findAll方法调用的sql语句
com.itheima.dao.UserDao.findAll
代码实现
1.导入jar包
2.编写配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
3.编写我们的逻辑
user接口
package com.itheima.dao;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper {
// 查询所有用户信息
List<User> findAll();
// 根据id查询
User findById(int id);
// 添加
int insertUser(User user);
int insertUser1(User user);
// 修改
int updateUser(Map<String,Object> userMap);
删除
int deleteUser(int id);
// 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
List<User> findUserByMohu(@Param("name") String username);
/**
* 将user表中的数据封装到对应的Person中
* @return
*/
List<Person> findUserToPerson();
/**
* 参数罗列时,必须给参数起别名
* @param username
* @param sex
* TODO: 请求参数有多个时,必须起别名
* @return
*/
List<User> findUserByTiaojian(@Param("username") String username,
@Param("sex") String sex);
/**
* 动态sql进行修改
* @return
*/
int updateUser1(User user);
/**
* 请求参数为数组
* @param ids
* @return
*/
List<User> findUserByIds1(int[] ids);
List<User> findUserByIds2(List<Integer> ids);
}
sql映射文件
<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
<!-- select 查询所有 -->
<select id="findAll" resultType="user">
select * from user
</select>
<!--
select标签: 表示查询,用于描述查询的sql语句
id: 唯一标识,找到唯一的一条sql语句
parameterType: 请求参数的类型
resultType: 返回值类型
返回值的全限定名(也可以使用别名)
TODO:获取请求参数: 在sql中获取请求携带的参数值
OGNL表达式: 获取请求携带的参数值
格式:
#{} : 占位符,底层使用PreparedStatement执行sql语句
${} : 字符串拼接,底层使用Statement执行sql语句
请求参数类型:
基本类型或String:
#{随便写}
${value}
pojo实体对象
#{属性名}
list
map
...
-->
<!--<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{随便写}
</select>-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = ${value}
</select>
<!--
增删改,默认返回int(影响的行数),此返回值不需要设置
OGNL: 获取pojo对象中的数据
#{属性名}
-->
<!--
resultType: 主键类型
keyColumn: 主键字段名称
keyProperty: 将查询结果赋给实体对象中的哪个属性
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
-->
<insert id="insertUser" parameterType="user">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
</insert>
<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 修改操作:
OGNL表达式: 获取map中的值
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user set username=#{username},birthday=#{birthday},
sex=#{sex},address=#{address} where id=#{id}
</update>
<!-- 删除 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!-- 模糊查询 -->
<select id="findUserByMohu" parameterType="string" resultType="user">
select * from user where username like concat("%",#{name},"%");
</select>
<!-- 别名查询,将查询结果封装到指定对象中 -->
<!--<select id="findUserToPerson" resultType="Person">
SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
</select>-->
<select id="findUserToPerson" resultMap="userToPersonMap">
SELECT * FROM user ;
</select>
<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
<resultMap id="userToPersonMap" type="Person">
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
select * from user
select * from user where username like concat('%',#{username},'%')
select * from user where sex = #{sex}
select * from user where username like concat('%',#{username},'%') and sex = #{sex}
-->
<select id="findUserByTiaojian" resultType="User">
select * from user
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<!-- 动态修改 -->
<update id="updateUser1" parameterType="User">
update user
<set>
<if test="username!=null and username!=''">
username=#{username},
</if>
<if test="birthday!=null and birthday!=''">
birthday=#{birthday},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
<if test="address!=null and address!=''">
address=#{address},
</if>
</set>
where id=#{id}
</update>
<!-- 遍历数组 -->
<select id="findUserByIds1" parameterType="int[]" resultType="user">
select * from user
<where>
id in
<foreach collection="array" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
<!-- 遍历list集合 -->
<select id="findUserByIds2" parameterType="list" resultType="user">
select * from user
<where>
id in
<foreach collection="list" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
</mapper>
测试代码
package com.itheima.test;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.*;
public class TestMybatis {
@Test
public void test01_FindAll(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findAll();
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test02_findById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = mapper.findById(5);
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 需求: 添加完毕后,获取最新添加的数据的id值
*/
@Test
public void test03_insertUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("托塔李天王1");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("陈塘关");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
@Test
public void test03_insertUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("嫦娥");
user.setSex("女");
user.setBirthday(new Date());
user.setAddress("月宫");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 修改
*/
@Test
public void test04_updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
Map<String, Object> map = new HashMap<>();
map.put("id",14);
map.put("username","玉皇大帝");
map.put("sex","男");
map.put("birthday",new Date());
map.put("address","天庭");
int i = mapper.updateUser(map);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test05_deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int i = mapper.deleteUser(10);
if(i>0){
System.out.println("删除成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test06_findUserByMohu(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByMohu("精");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test07_findUserToPerson(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Person> list = mapper.findUserToPerson();
for (Person person : list) {
System.out.println(person);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test08_findUserByTiaojian(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByTiaojian("精","女");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test09_updateUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setId(15);
user.setUsername("嫦娥");
user.setSex("男");
user.setAddress("月亮之上");
int i = mapper.updateUser1(user);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test10_findUserByIds1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int []arr = {1,3,4,5,6};
List<User> list = mapper.findUserByIds1(arr);
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test11_findUserByIds2(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(6);
List<User> list2 = mapper.findUserByIds2(list);
for (User user : list2) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
}
Mybatis核心API
SqlSessionFactoryBuilder:
1.解析核心配置文件,以及关联的sql映射文件
2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
1.封装了jdbc操作,增删改查
selectList("sql语句的id");
selectOne("...",参数);
insert("...");
update("...");
delete("...");
2.getMapper
生成dao接口的实现类对象(代理类)
3.事务控制的方法
commit();
rollback();
close();
sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
Conn conn;
// 第一个线程 : 1 张三
// 第二个线程 : 1 王五
public int update(String name ,int id ){
update 表名 set name = ? where id = ? ;
}
}
增删改查
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="com.itheima.pojo.User">
select * from user;
</select>
<!--
parameterType: 传入参数类型
可以传递的参数类型
基本数据类型 和 String
pojo对象
数组
list
map
编写格式:
以上类型的全限定名
基本数据类型 和 String: 直接编写类型名称: int _int
pojo对象: com.itheima.pojo.User
数组: _int[] int[]
list: list
map: map
ognl表达式:
#{变量名称}: 占位符
preparedStatement
pojo: 实体对象的属性名称
${变量名称}: 字符串拼接
Statement: 存在sql注入的风险
-->
<insert id="insertUser" parameterType="com.itheima.pojo.User">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 添加完成后,返回新增记录的id值
useGeneratedKeys: 开启获取主键自增的值 开关
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
-->
<insert id="insertUser1" parameterType="com.itheima.pojo.User"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<!-- 返回新增记录的id值
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
resultType: 返回值类型
order: 添加记录前或后
-->
<!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>-->
</insert>
<!-- 修改
出入参数: map
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user
set
username=#{username},
address=#{address},
sex=#{sex},
birthday=#{birthday}
where id = #{id}
</update>
<!-- 当传入参数为一个基本类型或String时,
#{随便写}
最好见名知意
-->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!--
如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
-->
<select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
<!-- select * from user where username like '%${name}%' -->
select * from user where username like concat('%',#{name},'%');
</select>
<!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
<select id="findUserToPerson" resultMap="findUserToPersonMap">
select * from user;
</select>
<!-- id: 当前resultMap的唯一标识
type: 将当前的一条查询结果封装的对象类型
-->
<resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
<!-- column: 数据库字段名称
property: 实体属性名称
-->
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
</mapper>
sql映射文件中的相关配置
作用: 主要用于编写sql语句
传入参数:
属性: parameterType
返回结果:
属性: resultType
属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
基本类型和String: 直接使用对应类型的类型名称即可
int long
pojo类型: 编写pojo的全限定名
全限定名= 包名+类名;
com.itheima.pojo.User
使用别名(别名需要在核心配置文件中进行配置)
map: map
list: list
数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
在idea中按两次 shift 键
TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
格式:
#{变量名称}: 占位符,preparedStatement
pojo: 实体对象的属性名称
map: 通过map的key获取value的值
基本类型或String:
#{随便定义} : 最好见名知意
list: 动态sql遍历
数组: 动态sql遍历
${变量名称}: 字符串拼接,Statement,存在sql注入的风险
基本类型或String:
${value} : 固定值
可以在参数列表中使用@Param("别名")给传入的参数起别名
动态sql
<!-- 抽取公共的sql语句 -->
<sql id="userSql">
select * from user
</sql>
<!-- 多条件查询 -->
<select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
<!-- 引用公共的sql语句 -->
<include refid="userSql"></include>
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<update id="updateUser1" parameterType="com.itheima.pojo.User">
update user
<set>
<if test="username!=null and username!='' ">
username=#{username},
</if>
<if test="address!=null and address!='' ">
address=#{address},
</if>
<if test="sex!=null and sex!='' ">
sex=#{sex},
</if>
<if test="birthday!=null">
birthday=#{birthday}
</if>
</set>
where id = #{id}
</update>
<select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
<select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
多表查询
一对一
-- 创建用户基本表 User实体
drop table if exists user;
-- 创建用户基本表
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
-- 用户描述信息表 UserInfo实体
create table user_info (
id int primary key, -- 既是主键又是外键
height double, -- 身高厘米
weight double, -- 体重公斤
married tinyint, -- 是否结婚,1为结婚,0为未婚
foreign key (id) references user(id)
);
-- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
-- ========================== java对象
User.java 封装用户的信息以及对应的描述信息
private id
private username
private birthday
private sex
private address
private UserInfo userInfo;
UserInfo.java 封装用户的描述信息,以及对应的用户信息
id
height
weight
married
User user;
多表查询的结果我们可以采用java的实体嵌套
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<select id="findUserAndUserInfo" resultMap="resultMap1">
SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对一的映射数据信息 -->
<association property="userInfo">
<id column="uiid" property="id"></id>
<result column="height" property="height"></result>
<result column="weight" property="weight"></result>
<result column="married" property="married"></result>
</association>
</resultMap>
</mapper>
一对多
-- 创建用户基本表 User实体
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
-- 创建订单表
create table orders(
oid int primary key auto_increment , -- 主键
user_id int not null, -- 用户id,外键
number varchar(20), -- 订单编号
create_time datetime, -- 下单时间
note varchar(100), -- 备注
foreign key(user_id) references user(id) -- 外键约束,关联主表的主键
);
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');
User.java 封装用户信息以及对应的订单信息
private id
private username
private birthday
private sex
private address
// 存放当前用户所拥有的多个订单
private List<Orders> ordersList;
Orders.java
oid
user_id
number
create_time
note
在一对多查询时,在一的一方提供多的一方的实体List集合
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<!-- 一对多查询 -->
<select id="findUserAndOrders" resultMap="resultMap1">
SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对多的映射关系 -->
<!--
property: 实体中对应属性的名称
javaType: 该属性对应的java的类型
ofType: 该属性对应的泛型类型
-->
<collection property="ordersList" javaType="list" ofType="orders">
<id column="oid" property="oid"></id>
<result column="user_id" property="user_id"></result>
<result column="number" property="number"></result>
<result column="create_time" property="create_time"></result>
<result column="note" property="note"></result>
</collection>
</resultMap>
</mapper>
多对多
-- 创建用户基本表 User实体
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
-- 角色
CREATE TABLE `role` (
role_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '角色id(主键)',
role_name VARCHAR(32) NOT NULL COMMENT '角色名称',
role_detail VARCHAR(100) DEFAULT NULL COMMENT '角色描述'
);
-- 插入角色记录
INSERT INTO role(role_name,role_detail) VALUES('校长','全校的管理者');
INSERT INTO role(role_name,role_detail) VALUES('讲师','传道授业解惑');
INSERT INTO role(role_name,role_detail) VALUES('班主任','班级的灵魂');
INSERT INTO role(role_name,role_detail) VALUES('助教','大家的朋友');
-- 中间表
CREATE TABLE user_role (
user_id INT NOT NULL COMMENT '用户id',
role_id INT NOT NULL COMMENT '角色id',
PRIMARY KEY (user_id,role_id), -- 复合主键
FOREIGN KEY (user_id) REFERENCES `user`(id),
FOREIGN KEY (role_id) REFERENCES role(role_id)
);
INSERT INTO user_role(user_id,role_id) VALUES(1,1); -- 1号用户对应1号角色
INSERT INTO user_role(user_id,role_id) VALUES(2,2);
INSERT INTO user_role(user_id,role_id) VALUES(6,2);
INSERT INTO user_role(user_id,role_id) VALUES(1,3);
INSERT INTO user_role(user_id,role_id) VALUES(2,1);
INSERT INTO user_role(user_id,role_id) VALUES(2,4);
-- ============================= 多对多
User.java 封装用户信息,以及用户对应的多个角色信息
private id
private username
private birthday
private sex
private address
private List<Role> roleList;
Role.java 封装角色信息,以及当前角色所属的多个用户信息
role_id
role_name
role_detail
List<User> userList;
课堂代码
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<!-- 一对多查询 -->
<select id="findUserAndRole" resultMap="resultMap1">
SELECT * FROM `user` u
LEFT JOIN user_role ur ON u.`id` = ur.`user_id`
LEFT JOIN role r ON ur.`role_id` = r.`role_id`;
</select>
<!-- 封装用户表的数据信息 -->
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</resultMap>
<resultMap id="resultMap1" type="user" extends="userResultMap">
<!-- 配置一对多的映射关系 -->
<!--
property: 实体中对应属性的名称
javaType: 该属性对应的java的类型
ofType: 该属性对应的泛型类型
-->
<collection property="roleList" javaType="list" ofType="role">
<id column="role_id" property="role_id"></id>
<result column="role_name" property="role_name"></result>
<result column="role_detail" property="role_detail"></result>
</collection>
</resultMap>
</mapper>
延迟加载(懒加载)
什么时候使用什么时候加载(查询)
一对一的延迟加载
# 查询所有用户信息以及对应的详细信息
select * from user u left join user_info ui on u.id = ui.id;
拆分
1.确定主表 user
查询主表的所有数据信息
select * from user;
2.根据关联条件,查询从表 userInfo
根据主表的id查询对应的详情
select * from user_info where id = #{id} ;
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
注意: 注意该标签编写的位置
<!-- 配置Mybatis的全局属性 -->
<settings>
<!-- 开启对懒加载的支持 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.配置懒加载
<!-- 查询所有用户信息 -->
<select id="findAll" resultMap="userResultMap">
select * from user;
</select>
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- property: 实体属性名称
select: 对应的sql语句所在的位置 id
column: 对应sql语句执行时的条件 -->
<association property="userInfo" select="findUserInofById" column="id"></association>
</resultMap>
<!-- 根据id查询用户详情 -->
<select id="findUserInofById" resultType="userinfo">
select * from user_info where id = #{id}
</select>
一对多的延迟加载
# 查询所有用户信息以及对应的订单详情
SELECT * FROM `user` u LEFT JOIN orders o ON u.`id`=o.`user_id` ;
拆分
1.确定主表 user
查询所有用户信息
select * from user;
2.根据关联条件,查询从表 orders
根据用户id查询当前用户拥有的订单
select * from orders where user_id = #{id}
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
注意: 注意该标签编写的位置
<!-- 配置Mybatis的全局属性 -->
<settings>
<!-- 开启对懒加载的支持 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.配置一对多延迟加载
<!-- 查询所有用户信息 -->
<select id="findAll" resultMap="userResultMap">
select * from user;
</select>
<resultMap id="userResultMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对多的延迟加载 -->
<collection property="ordersList" javaType="list" ofType="orders"
select="findOrdersByUid" column="id"></collection>
</resultMap>
<!-- 根据用户id查询当前用户所拥有的订单 -->
<select id="findOrdersByUid" resultType="orders">
select * from orders where user_id = #{user_id}
</select>
三 注解方式实现Mybatis
将相关sql的配置到注解上,mybatis自动解析和加载
Mybatis常用注解:
注释: 对代码的解释说明,是给程序员看的
注解: 对代码的说明,是给jvm虚拟查看
作用: 可以代替配置文件
@Insert 添加
value属性: sql语句
@Options:可选配置(获取主键)
userGeneratedKeys:开关
keyProperty :对象属性
@Update:更新
Value:sql语句
@Delete : 删除
Value:sql语句
@Select : 查询
Value:sql语句
@SelectProvider : 拼接动态sql
配置查询结果和实体属性的映射关系:
@Results:声明映射关系的配置
Value:接受@Result的数组
@Result:
id: true(默认值为false)
property = "实体中的属性名"
column = "查询结果列名"
@Result:配置映射关系
Id:(boolean)声明是否为主键配置
Property:对象中的属性名
Column:查询的字段名
----------------------- 单表
查询所有用户信息
条件查询
模糊查询
聚合查询
添加用户信息
修改用户信息
删除用户信息
----------------------- 多表
一对一
一对多
注解的一对一映射
// 注意: 在Mybatis的核心配置文件中开启懒加载
延迟加载(懒加载)
// 查询所有用户信息
@Select("select * from user ;")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(
column = "id", // 懒加载需要传递的参数
property = "userInfo", // 懒加载的结果需要封装到哪个属性上
javaType = UserInfo.class, // 懒加载返回的结果的数据类型
one=@One(
// 懒加载时调用的sql语句的位置
select = "com.itheima.dao.UserDao.findUserInofById",
fetchType=FetchType.LAZY // 懒加载
)
)
})
List<User> findAll();
// 根据id查询用户详情
@Select("select * from user_info where id = #{id}")
UserInfo findUserInofById(int id);
注解的一对多映射
// 查询所有用户信息
@Select("select * from user ;")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(
column = "id", // 传递给延迟加载方法的参数
property = "ordersList", // 延迟加载结果封装的属性名称
javaType = List.class, // 属性的类型
many = @Many(
// 延迟加载sql语句的位置
select = "com.itheima.dao.UserDao.findOrdersByUid",
fetchType = FetchType.LAZY // 设置延迟加载
)
)
})
List<User> findAll();
// 根据用户id查询当前用户所拥有的订单信息
@Select("select * from orders where user_id = #{user_id}")
List<Orders> findOrdersByUid(int user_id);
Mybatis中的缓存(了解)
缓存: 临时存放,将数据临时存放到内存中,当程序停止后,内存就会被释放
作用: 降低数据库的压力
Mybatis的缓存:
一级缓存: sqlSession级别的缓存,是Mybatis自带的,关不掉,必须使用
二级缓存: 可以理解为是SqlSessionFactory基本的缓存,多个SQLSession之间可以共享
1.在Mybatis的核心配置文件中开启对二级缓存的支持
<setting name="cacheEnabled" value="true"/>
2.需要缓存的实体对象必须实现序列化接口
3.在sql映射文件中开启缓存支持
<!-- 开启对二级缓存的支持 -->
<cache/>
<!-- 查询所有用户信息 -->
<select id="findUserById" resultType="USer" useCache="true">
select * from user where id = #{id};
</select>
4.sqlSession提交和关闭
总结
Mybatis框架:
持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
Mybatis结构:
两类配置文件:
核心配置文件:
存放连接数据库的数据信息
1.设置加载的properties配置文件(获取连接数据库的基本信息)
2.设置别名(给类的全限定名起别名)
3.设置操作数据库时使用JDBC的事务,和连接池
4.设置sql映射文件的位置
sql映射文件:
存放sql语句
namespace: 用于区分多个sql映射文件
id: sql语句的唯一标识.
<select></select>
<insert></insert>
<delete></delete>
<update></update>
编写自己的业务代码:
传统方式:
在dao层编写业务接口,提供相关方法
编写接口的实现类,手动调用Mybatis提供的相关API
动态代理方式:
在dao层编写业务接口,提供相关方法
程序启动时:
程序启动时,优先解析所有的配置文件,将解析到的数据存放到Configuration对象中
Configuration对象:
别名配置
连接数据库的基本信息: url driver username password
Map<key,value>
key: namespace.id
value: MappedStatement
sql: sql语句
parameterType: 请求参数类型
resultType: 返回结果类型
...
API:
SqlSessionFactoryBuilder:负责解析配置文件
SqlSessionFactory: 线程安全的对象
负责创建SqlSession对象并将解析到的Configuration传递给SqlSession
SqlSession: 不是线程安全的对象
提供了操作数据库的相关方法,在相关方法中封装了JDBC操作完成增删改查
selectList(参数1,参数2);
selectOne(参数1,参数2);
insert(参数1,参数2);
update(参数1,参数2);
delete(参数1,参数2);
commit();
rollback();
close();
T getMapper(T.class);
传统方式: 了解
动态代理方式: ★★★
导入jar包
导入核心配置文件(log4j配置文件)
编写user业务的接口,提供相关方法
在user业务对应的sql映射文件中编写sql语句
namespace: 接口的全限定名
id: 接口中的方法名称
------------------------------------------------
核心配置文件:
1.设置加载的properties配置文件(获取连接数据库的基本信息)
2.设置别名(给类的全限定名起别名)
3.设置操作数据库时使用JDBC的事务,和连接池
4.设置sql映射文件的位置
Sql映射文件:
<select></select>
<insert></insert>
<delete></delete>
<update></update>
传入参数类型:
基本类型和String:
直接写对应类型的名称即可
pojo对象:
全限定名
别名
map: map
list: list
数组: int[] _int[]
获取传入参数的值:
OGNL表达式:获取传入参数的值
格式:
#{} 占位符,preparedStatement对象
${} 拼接符,Statement对象
基本类型和String:
#{随便写} ${value}
pojo对象:
#{pojo对象中的属性名}
${pojo对象中的属性名}
map: map
#{map的key}
${map的key}
list: list
遍历
数组: int[] _int[]
遍历
传出参数类型:
基本类型和String:
直接写对应类型的名称即可
pojo对象:
全限定名
别名
list<泛型>:
使用泛型类型的全限定名或别名(将一条记录封装到哪个对象中)
回顾
1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
1.导入jar包
log4j日志包
mysql驱动包
mybatis的jar包
2.导入配置文件
log4j日志包
mybatis核心配置文件 xml
sql映射文件
3.编写代码
传统方式:
配置完核心配置文件后
直接在sql映射文件中编写sql语句
调用sqlSession的API,指定sql语句,执行方法
动态代理方式:
配置完核心配置文件后
在sql映射文件中编写sql语句
编写dao层的接口
调用sqlSession的getMapper方法,生成接口的实现类(代理类),
在代理类中调用Sqlsession的相关方法完成增删改查
API:
SqlSessionFactoryBuilder: 解析
作用: 解析配置文件(核心配置文件,sql映射文件)
方法: build(is);
SqlSessionFactory: 线程安全(内部没有共享的变量)
作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
方法: openSession(boolean);
SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
方法:
selectList("namespace.id",参数);
selectOne("namespace.id",参数);
insert("namespace.id",参数);
update("namespace.id",参数);
delete("namespace.id",参数);
rollback();
commit();
close();
T getMapper(T.class);
底层使用动态代理,生成接口的实现类,
在接口的实现类方法中调用以上方法完成增删改查
Mybatis
作用: 对jdbc进行了封装,将sql语句与java代码分离
一 传统方式实现Mybatis
程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)
入门实现
1.导入jar包
2.准备mybatis的配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
sql映射文件-user
<?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="user">
<!-- select 查询所有 -->
<select id="queryAll" resultType="user">
select * from user
</select>
<!-- select 一条记录 -->
<select id="queryOne" resultType="user" parameterType="int">
select * from user where id = #{id}
</select>
</mapper>
sql映射文件-product
<?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="product">
<!-- select 查询所有 -->
<select id="queryAll" resultType="product">
select * from product
</select>
</mapper>
启动解析过程
xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
String url;
String driver;
String username;
String password;
Map<String,Mapper>
key:String,存放当前sql的唯一标识
sql语句标签上id属性的值
命名空间.id
value: Mapper,当前的sql语句及返回值对象
Mapper.java 一个sql语句对应一个Mapper
String sql; // 配置文件中的sql语句
String resultType; // sql执行后返回的数据类型
String parameterType; // sql执行时需要传入的参数类型
3.编写自己的业务
mybatis提供的相关API方法
Mybatis封装好的方法:
SqlSession提供操作数据库的方法
参数1: mapperId = namespace.id; 找到对应的sql语句
参数2: 执行当前sql需要使用的参数
selectList("mapperId",参数...);
selectOne("mapperId",参数...);
insert("mapperId",参数...);
update("mapperId",参数...);
delete("mapperId",参数...);
在以上方法中封装了JDBC操作
commit();
rollback();
close();
创建接口的实现类对象(代理类)
getMapper(Class ...);
user业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
List<User> findAll() throws IOException;
User findById(int id);
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
/**
* 传统方式:
* 手动调用Mybatis提供的方法,完成增删改查
*/
public class UserMapperImpl implements UserMapper {
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<User> list = sqlSession.selectList("user.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
User user = sqlSession.selectOne("user.queryOne", id);
MybatisUtils.close(sqlSession);
return user;
}
/* private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<User> findAll() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("user.queryAll");
return list;
}
@Override
public User findById(int id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.queryOne", id);
return user;
}*/
}
product业务
接口代码
package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
List<Product> findAll();
}
实现类代码
package com.itheima.dao.impl;
import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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.IOException;
import java.io.InputStream;
import java.util.List;
public class ProductMapperImpl implements ProductMapper {
@Override
public List<Product> findAll() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<Product> list = sqlSession.selectList("product.queryAll");
MybatisUtils.close(sqlSession);
return list;
}
/*private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<Product> findAll() {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Product> list = sqlSession.selectList("product.queryAll");
sqlSession.close();
return list;
}*/
}
Mybatis工具类
package com.itheima.utils;
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.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory ;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession对象(默认手动提交事务)
* @return
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
/**
* 根据传递的参数,返回具体的sqlSession对象
* @param flag
* @return
*/
public static SqlSession getSqlSession(boolean flag){
return sqlSessionFactory.openSession(flag);
}
public static void close(SqlSession sqlSession){
if (sqlSession!=null){
sqlSession.close();
}
}
}
Log4j日志
1.导入jar包
2.导入配置文件
二 动态代理方式实现Mybatis★
程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行
约定大于配置:
框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定:
mybatis在定位sql语句时,使用的是 接口的全限定名.方法名称
例子: 查找findAll方法调用的sql语句
com.itheima.dao.UserDao.findAll
代码实现
1.导入jar包
2.编写配置文件
一类: mybatis核心配置文件(sqlMapConfig.xml mybatisConfig.xml)
1.环境
配置mybatis使用的连接池
配置连接数据库的基本信息:
username password url driver
2.配置sql映射文件的位置
二类: sql映射文件
作用: 编写sql语句
<select></select>
<insert></insert>
<update></update>
<delete></delete>
核心配置文件
<?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>
<!-- 加载指的properties配置文件 -->
<properties resource="db.properties"></properties>
<!-- 给类的全限定名起别名 -->
<typeAliases>
<!-- 给一个类起别名 -->
<!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
<!-- TODO:最终使用方式,给一个包下的所有类起别名
别名为包下类的类名称,不区分大小写
-->
<package name="com.itheima.pojo"></package>
</typeAliases>
<!-- TODO:Mybatis核心配置文件:
environments: 环境-连接数据库的环境
mappers: 映射,sql语句 映射文件在哪个位置
-->
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器:由JDBC管理事务 -->
<transactionManager type="JDBC"/>
<!--数据源:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次自己创建连接
3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载其他的映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/ProductMapper.xml"></mapper>
</mappers>
</configuration>
3.编写我们的逻辑
user接口
package com.itheima.dao;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper {
// 查询所有用户信息
List<User> findAll();
// 根据id查询
User findById(int id);
// 添加
int insertUser(User user);
int insertUser1(User user);
// 修改
int updateUser(Map<String,Object> userMap);
删除
int deleteUser(int id);
// 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
List<User> findUserByMohu(@Param("name") String username);
/**
* 将user表中的数据封装到对应的Person中
* @return
*/
List<Person> findUserToPerson();
/**
* 参数罗列时,必须给参数起别名
* @param username
* @param sex
* TODO: 请求参数有多个时,必须起别名
* @return
*/
List<User> findUserByTiaojian(@Param("username") String username,
@Param("sex") String sex);
/**
* 动态sql进行修改
* @return
*/
int updateUser1(User user);
/**
* 请求参数为数组
* @param ids
* @return
*/
List<User> findUserByIds1(int[] ids);
List<User> findUserByIds2(List<Integer> ids);
}
sql映射文件
<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
<!-- select 查询所有 -->
<select id="findAll" resultType="user">
select * from user
</select>
<!--
select标签: 表示查询,用于描述查询的sql语句
id: 唯一标识,找到唯一的一条sql语句
parameterType: 请求参数的类型
resultType: 返回值类型
返回值的全限定名(也可以使用别名)
TODO:获取请求参数: 在sql中获取请求携带的参数值
OGNL表达式: 获取请求携带的参数值
格式:
#{} : 占位符,底层使用PreparedStatement执行sql语句
${} : 字符串拼接,底层使用Statement执行sql语句
请求参数类型:
基本类型或String:
#{随便写}
${value}
pojo实体对象
#{属性名}
list
map
...
-->
<!--<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{随便写}
</select>-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = ${value}
</select>
<!--
增删改,默认返回int(影响的行数),此返回值不需要设置
OGNL: 获取pojo对象中的数据
#{属性名}
-->
<!--
resultType: 主键类型
keyColumn: 主键字段名称
keyProperty: 将查询结果赋给实体对象中的哪个属性
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
-->
<insert id="insertUser" parameterType="user">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<selectKey resultType="int" keyColumn="id" keyProperty="id">
select last_insert_id();
</selectKey>
</insert>
<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 修改操作:
OGNL表达式: 获取map中的值
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user set username=#{username},birthday=#{birthday},
sex=#{sex},address=#{address} where id=#{id}
</update>
<!-- 删除 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!-- 模糊查询 -->
<select id="findUserByMohu" parameterType="string" resultType="user">
select * from user where username like concat("%",#{name},"%");
</select>
<!-- 别名查询,将查询结果封装到指定对象中 -->
<!--<select id="findUserToPerson" resultType="Person">
SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
</select>-->
<select id="findUserToPerson" resultMap="userToPersonMap">
SELECT * FROM user ;
</select>
<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
<resultMap id="userToPersonMap" type="Person">
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
select * from user
select * from user where username like concat('%',#{username},'%')
select * from user where sex = #{sex}
select * from user where username like concat('%',#{username},'%') and sex = #{sex}
-->
<select id="findUserByTiaojian" resultType="User">
select * from user
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<!-- 动态修改 -->
<update id="updateUser1" parameterType="User">
update user
<set>
<if test="username!=null and username!=''">
username=#{username},
</if>
<if test="birthday!=null and birthday!=''">
birthday=#{birthday},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
<if test="address!=null and address!=''">
address=#{address},
</if>
</set>
where id=#{id}
</update>
<!-- 遍历数组 -->
<select id="findUserByIds1" parameterType="int[]" resultType="user">
select * from user
<where>
id in
<foreach collection="array" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
<!-- 遍历list集合 -->
<select id="findUserByIds2" parameterType="list" resultType="user">
select * from user
<where>
id in
<foreach collection="list" open="(" close=")" separator="," item="ele">
#{ele}
</foreach>
</where>
</select>
</mapper>
测试代码
package com.itheima.test;
import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.*;
public class TestMybatis {
@Test
public void test01_FindAll(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findAll();
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test02_findById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = mapper.findById(5);
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 需求: 添加完毕后,获取最新添加的数据的id值
*/
@Test
public void test03_insertUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("托塔李天王1");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("陈塘关");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
@Test
public void test03_insertUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setUsername("嫦娥");
user.setSex("女");
user.setBirthday(new Date());
user.setAddress("月宫");
int i = mapper.insertUser(user);
if(i>0){
System.out.println("添加成功");
}
System.out.println(user);
MybatisUtils.close(sqlSession);
}
/**
* 修改
*/
@Test
public void test04_updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
Map<String, Object> map = new HashMap<>();
map.put("id",14);
map.put("username","玉皇大帝");
map.put("sex","男");
map.put("birthday",new Date());
map.put("address","天庭");
int i = mapper.updateUser(map);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test05_deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int i = mapper.deleteUser(10);
if(i>0){
System.out.println("删除成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test06_findUserByMohu(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByMohu("精");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test07_findUserToPerson(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Person> list = mapper.findUserToPerson();
for (Person person : list) {
System.out.println(person);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test08_findUserByTiaojian(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<User> list = mapper.findUserByTiaojian("精","女");
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test09_updateUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
User user = new User();
user.setId(15);
user.setUsername("嫦娥");
user.setSex("男");
user.setAddress("月亮之上");
int i = mapper.updateUser1(user);
if(i>0){
System.out.println("修改成功");
}
MybatisUtils.close(sqlSession);
}
@Test
public void test10_findUserByIds1(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
int []arr = {1,3,4,5,6};
List<User> list = mapper.findUserByIds1(arr);
for (User user : list) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
@Test
public void test11_findUserByIds2(){
SqlSession sqlSession = MybatisUtils.getSqlSession(true);
//获取接口的实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用对象中的方法
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(6);
List<User> list2 = mapper.findUserByIds2(list);
for (User user : list2) {
System.out.println(user);
}
MybatisUtils.close(sqlSession);
}
}
Mybatis核心API
SqlSessionFactoryBuilder:
1.解析核心配置文件,以及关联的sql映射文件
2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
1.封装了jdbc操作,增删改查
selectList("sql语句的id");
selectOne("...",参数);
insert("...");
update("...");
delete("...");
2.getMapper
生成dao接口的实现类对象(代理类)
3.事务控制的方法
commit();
rollback();
close();
sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
Conn conn;
// 第一个线程 : 1 张三
// 第二个线程 : 1 王五
public int update(String name ,int id ){
update 表名 set name = ? where id = ? ;
}
}
增删改查
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="com.itheima.pojo.User">
select * from user;
</select>
<!--
parameterType: 传入参数类型
可以传递的参数类型
基本数据类型 和 String
pojo对象
数组
list
map
编写格式:
以上类型的全限定名
基本数据类型 和 String: 直接编写类型名称: int _int
pojo对象: com.itheima.pojo.User
数组: _int[] int[]
list: list
map: map
ognl表达式:
#{变量名称}: 占位符
preparedStatement
pojo: 实体对象的属性名称
${变量名称}: 字符串拼接
Statement: 存在sql注入的风险
-->
<insert id="insertUser" parameterType="com.itheima.pojo.User">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 添加完成后,返回新增记录的id值
useGeneratedKeys: 开启获取主键自增的值 开关
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
-->
<insert id="insertUser1" parameterType="com.itheima.pojo.User"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user values(null,#{username},#{birthday},#{sex},#{address});
<!-- 返回新增记录的id值
keyColumn: 数据库主键字段名称
keyProperty: 实体中属性的名称
resultType: 返回值类型
order: 添加记录前或后
-->
<!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>-->
</insert>
<!-- 修改
出入参数: map
#{map的key}
-->
<update id="updateUser" parameterType="map">
update user
set
username=#{username},
address=#{address},
sex=#{sex},
birthday=#{birthday}
where id = #{id}
</update>
<!-- 当传入参数为一个基本类型或String时,
#{随便写}
最好见名知意
-->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!--
如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
-->
<select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
<!-- select * from user where username like '%${name}%' -->
select * from user where username like concat('%',#{name},'%');
</select>
<!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
<select id="findUserToPerson" resultMap="findUserToPersonMap">
select * from user;
</select>
<!-- id: 当前resultMap的唯一标识
type: 将当前的一条查询结果封装的对象类型
-->
<resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
<!-- column: 数据库字段名称
property: 实体属性名称
-->
<id column="id" property="pid"></id>
<result column="username" property="pusername"></result>
<result column="birthday" property="pbirthday"></result>
<result column="sex" property="psex"></result>
<result column="address" property="paddress"></result>
</resultMap>
</mapper>
sql映射文件中的相关配置
作用: 主要用于编写sql语句
传入参数:
属性: parameterType
返回结果:
属性: resultType
属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
基本类型和String: 直接使用对应类型的类型名称即可
int long
pojo类型: 编写pojo的全限定名
全限定名= 包名+类名;
com.itheima.pojo.User
使用别名(别名需要在核心配置文件中进行配置)
map: map
list: list
数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
在idea中按两次 shift 键
TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
格式:
#{变量名称}: 占位符,preparedStatement
pojo: 实体对象的属性名称
map: 通过map的key获取value的值
基本类型或String:
#{随便定义} : 最好见名知意
list: 动态sql遍历
数组: 动态sql遍历
${变量名称}: 字符串拼接,Statement,存在sql注入的风险
基本类型或String:
${value} : 固定值
可以在参数列表中使用@Param("别名")给传入的参数起别名
动态sql
<!-- 抽取公共的sql语句 -->
<sql id="userSql">
select * from user
</sql>
<!-- 多条件查询 -->
<select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
<!-- 引用公共的sql语句 -->
<include refid="userSql"></include>
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
</where>
</select>
<update id="updateUser1" parameterType="com.itheima.pojo.User">
update user
<set>
<if test="username!=null and username!='' ">
username=#{username},
</if>
<if test="address!=null and address!='' ">
address=#{address},
</if>
<if test="sex!=null and sex!='' ">
sex=#{sex},
</if>
<if test="birthday!=null">
birthday=#{birthday}
</if>
</set>
where id = #{id}
</update>
<select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
<select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
<include refid="userSql"></include>
<where>
id in
<!-- collection: 被遍历的对象类型
array: 表示遍历数组
list: 表示遍历list集合
item: 将遍历到的数组赋值给此变量
open: 以什么开头
close: 以什么结尾
separator: 用什么分割
-->
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
多表查询
一对一
-- 创建用户基本表 User实体
drop table if exists user;
-- 创建用户基本表
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
-- 用户描述信息表 UserInfo实体
create table user_info (
id int primary key, -- 既是主键又是外键
height double, -- 身高厘米
weight double, -- 体重公斤
married tinyint, -- 是否结婚,1为结婚,0为未婚
foreign key (id) references user(id)
);
-- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
-- ========================== java对象
User.java 封装用户的信息以及对应的描述信息
private id
private username
private birthday
private sex
private address
private UserInfo userInfo;
UserInfo.java 封装用户的描述信息,以及对应的用户信息
id
height
weight
married
User user;
多表查询的结果我们可以采用java的实体嵌套
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<select id="findUserAndUserInfo" resultMap="resultMap1">
SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对一的映射数据信息 -->
<association property="userInfo">
<id column="uiid" property="id"></id>
<result column="height" property="height"></result>
<result column="weight" property="weight"></result>
<result column="married" property="married"></result>
</association>
</resultMap>
</mapper>
一对多
-- 创建用户基本表 User实体
create table user (
id int primary key auto_increment,
username varchar(20) not null,
birthday date,
sex char(1) default '男',
address varchar(50)
);
-- 创建订单表
create table orders(
oid int primary key auto_increment , -- 主键
user_id int not null, -- 用户id,外键
number varchar(20), -- 订单编号
create_time datetime, -- 下单时间
note varchar(100), -- 备注
foreign key(user_id) references user(id) -- 外键约束,关联主表的主键
);
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');
User.java 封装用户信息以及对应的订单信息
private id
private username
private birthday
private sex
private address
// 存放当前用户所拥有的多个订单
private List<Orders> ordersList;
Orders.java
oid
user_id
number
create_time
note
在一对多查询时,在一的一方提供多的一方的实体List集合
<?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映射文件添加一个唯一标识-->
<!--
约定:
namespace: 必须为对应的接口的全限定名
标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 查询所有用户信息 -->
<select id="findAll" resultType="USer">
select * from user;
</select>
<!-- 一对多查询 -->
<select id="findUserAndOrders" resultMap="resultMap1">
SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
</select>
<resultMap id="resultMap1" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!-- 配置一对多的映射关系 -->
<!--
property: 实体中对应属性的名称
javaType: 该属性对应的java的类型
ofType: 该属性对应的泛型类型
-->
<collection property="ordersList" javaType="list" ofType="orders">
<id column="oid" property="oid"></id>
<result column="user_id" property="user_id"></result>
<result column="number" property="number"></result>
<result column="create_time" property="create_time"></result>
<result column="note" property="note"></result>
</collection>
</resultMap>
</mapper>