MyBatis介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatement、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
MyBatis快速入门
- 导入 MyBatis jar包
配置 MyBatis 核心配置文件—SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 关联数据库jdbc --> <properties resource="db.properties"></properties> <!-- 和spring整合后 environments配置将废除 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <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> </configuration>
配置db.propertis
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/myfirstdb?characterEncoding\=utf-8 jdbc.username=root jdbc.password=root
配置log4j.properties
# Global logging configuration log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
创建Bean
public class User { private Integer id; private String username; private String password; private String sex;
测试
配置bean.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace:命名空间,做sql隔离 --> <mapper namespace="test"> </mapper>
在核心配置文件中添加引用
<mappers> <mapper resource="com/example/batis/domain/User.xml" /> </mappers> typeAliases>
测试查询
bean.xml中查询的方法
<select id="selectUserById" resultType="com.example.batis.domain.User" parameterType="int"> select * from t_user where id=#{id} </select> <select id="selectUser" resultType="user"> select * from t_user </select>
定义创建工厂方法
// 会话工厂 private SqlSessionFactory sqlSessionFactory; @Before public void createSqlSessionFactory() throws IOException { // 配置文件 String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); }
定义查询单个方法
@Test public void testQuery() { SqlSession openSession = sqlSessionFactory.openSession(); User user = openSession.selectOne("test.selectUserById", 5); System.out.println(user.toString()); openSession.close(); }
定义查询集合方法
@Test public void testQueryList() { SqlSession openSession = sqlSessionFactory.openSession(); List<User> user = openSession.selectList("test.selectUser"); for (User user2 : user) { System.out.println(user2.toString()); } openSession.close(); }
测试添加
<insert id="saveUser" parameterType="com.example.batis.domain.User"> insert into t_user (username,password,sex) values(#{username},#{password},#{sex}); </insert> @Test public void testInsert() { SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User("王五", "123", "男"); sqlSession.insert("test.saveUser", user); sqlSession.commit(); sqlSession.close(); }
测试修改
<update id="updateUser" parameterType="com.example.batis.domain.User"> update t_user set username=#{username},password=#{password},sex=#{sex} where id=#{id} </update> @Test public void testUpdate() { SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User("王小九", "1234", "女"); user.setId(5); sqlSession.update("test.updateUser", user); sqlSession.commit(); sqlSession.close(); }
测试删除
<delete id="deleteUser" parameterType="int" > delete from t_user where id=#{a} </delete> @Test public void testDelete() { SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.delete("test.deleteUser", 1); sqlSession.commit(); sqlSession.close(); }
测试模糊查询
<select id="selectUserLike" resultType="user"> select * from t_user where username like '%${value}%' </select> @Test public void testSelectUserLike() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User selectUserLike = userMapper.selectUserLike("王"); System.out.println(selectUserLike.toString()); }
{}和${}区别
#{}表示一个占位符号, 通过#{}可以实现preparedStatement向占位符中设置值, 自动进行java类型和jdbc类型转换,#{}括号中可以是value或其它名称 ${}表示拼接sql串${}括号中只能是value。 传入的内容拼接在sql中且不进行jdbc类型转换。
parameterType:指定输入参数类型
- resultType:指定输出结果类型
API详细分析及
SqlSessionFactoryBuilder
通过读取配置文件,创建sessionFactory String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory
会话工厂,用来创建会话 SqlSession openSession = sqlSessionFactory.openSession();
SqlSession
是一个面向用户的接口, sqlSession中定义了数据库操作方法。 每个线程都应该有它自己的SqlSession实例。 SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求是方法范围。 打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。
Dao类的封装
普通方式Dao封装
定义UserDao
public interface UserDao { public List<User> queryUser(); public User queryUserById(); public void saveUser(User user); public void updateUser(User user); public void deleteUser(int id); }
定义UserDaoImpl
public class UserDaoImpl implements UserDao { private SqlSessionFactory sqlSessionFactory; public UserDaoImpl() { // 配置文件 try { String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /** * 根据用户id删除用户 */ @Override public User queryUserById() { SqlSession openSession = sqlSessionFactory.openSession(); User user = openSession.selectOne("test.selectUserById", 5); openSession.close(); return user; } /** * 删除用户 */ @Override public void deleteUser(int id) { SqlSession openSession = sqlSessionFactory.openSession(); int delete = openSession.delete("test.deleteUser", id); System.out.println(delete); openSession.commit(); openSession.close(); }
动态代理方式封装
编写规范
Mapper接口开发需要遵循以下规范: 1、 Mapper.xml文件中的namespace与mapper接口的类路径相同。 2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同 3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同 4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
配置UserMapper.xml
<mapper namespace="com.example.batis.dao.UserMapper"> 其他配置和上述bean一致
创建UserMapper对象
public interface UserMapper { public List<User> selectUser() throws Exception; public User selectUserById() throws Exception; public void saveUser(User user) throws Exception; public void updateUser(User user) throws Exception; public void deleteUser(int id) throws Exception; }
测试
@Test public void testMapperQuery() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> queryUser = userMapper.selectUser(); for (User user : queryUser) { System.out.println(user.toString()); } }
配置详解
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties 关联properties文件
<properties resource="db.properties"/> MyBatis 将按照下面的顺序来加载属性: 在 properties 元素体内定义的属性首先被读取。 然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
typeAliases(类型别名)
别名 映射的类型 _byte byte _long long _short short _int int _integer int _double double _float float _boolean boolean string String byte Byte long Long short Short int Integer integer Integer double Double float Float boolean Boolean date Date decimal BigDecimal bigdecimal BigDecimal map Map
配置自定义别名
指定具体的类 <typeAlias type="com.example.batis.domain.User" alias="user" /> 指定包名,会扫描所有的bean类,别名以类名大小写定义即可 <package name="com.example.batis.domain" />
mappers
使用相对于类路径的资源
<mapper resource="com/example/batis/dao/UserMapper.xml" />
类路径
<mapper class="com.example.batis.dao.UserMapper" /> 此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
包路径
<package name="com.example.batis.dao" />
输入映射和输出映射
vo方式输入映射
定义vo对象,用来放置输入的数据
public class QueryVO { User user; public void setUser(User user) { this.user = user; } public User getUser() { return user; } }
mapper.xml中
<select id="getUserByUserNameAndSex" resultType="user" parameterType="com.example.mybatis.domain.QueryVO"> select * from t_user where username=#{user.username} and sex=#{user.sex} </select>
测试类中
@Test public void testQueryVO() { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); QueryVO queryVO = new QueryVO(); User user = new User(); user.setUsername("王小九"); user.setSex("女"); queryVO.setUser(user); List<User> selectUserLike = userMapper.getUserByUserNameAndSex(queryVO); for (User user2 : selectUserLike) { System.out.println(user2); } }
输出映射
普通方式输出映射
回顾知识
resultMap类型数据
特点:当列和字段不一致时,可以指定列和字段的对应关系 <select id="getUserListResultMap" resultMap="userListResultMap"> select id _id,username _username,password _password,sex _sex from t_user </select> 如果返回类型配置为 resultType="user",由于查询出来的column列名称不能和user中字段名名称对应,会导致出现错误 指定对象和数据库列的映射关系 <resultMap type="user" id="userListResultMap"> <id column="_id" property="id" /> <result column="_username" property="username" /> <result column="_password" property="password" /> <result column="_sex" property="password" /> </resultMap>
动态SQL
通过mybatis提供的各种标签方法实现动态拼接sql。
if 条件判断某些语句添加或者不添加
案例:多条件查询
回顾JDBC代码写法:
String sql="select * from t_user where 1=1"; if(user.getUsername()!=null&&user.getUsername()!=""){ sql=sql+"and username like "+user.getUsername(); } if(user.getSex()!=null&&user.getSex()!=""){ sql=sql+user.getSex(); }
mybatis中mapper.xml中配置
<select id="getConditionUser" resultType="user" parameterType="user"> select * from t_user where 1=1 <if test="username!=null and username!=''"> and username like '%${username}%' </if> <if test="sex!=null and sex!=''"> and sex=#{sex} </if> </select>
where 代替sql中的where
<select id="getConditionUser" resultType="user" parameterType="user"> select * from t_user <where> <if test="username!=null and username!=''"> and username like '%${username}%' </if> <if test="sex!=null and sex!=''"> and sex=#{sex} </if> </where> </select>
foreach 用法 通过遍历方式映射参数
xml中写法
<select id="getUserByIds" parameterType="com.example.mybatis.domain.QueryVO" resultType="user"> select * from t_user where 1=1 <foreach collection="ids" open="and id in(" close=")" separator="," item="id"> #{id} </foreach> </select> * 参数名称 collection 代表集合 open 代表开始sql语句 close 代表sql结束 seperator代表分割符 item 代表集合遍历过程中的对象
QueryVO中定义
public class QueryVO { public List<Integer> ids; public List<Integer> getIds() { return ids; } public void setIds(List<Integer> ids) { this.ids = ids; }
测试代码
@Test public void testForeach() { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); QueryVO queryVO=new QueryVO(); List<Integer> ids=new ArrayList<Integer>(); ids.add(1); ids.add(3); queryVO.setIds(ids); List<User> userByIds = userMapper.getUserByIds(queryVO); for (User user : userByIds) { System.out.println(user.toString()); } }