什么是Mybatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Mybatis作用
数据持久化:
持久化就是将程序的数据在持久状态和瞬时状态转换的过程
持久层主要是写完成持久化操作的代码块
而Mybatis就一个优秀的持久层框架
帮助程序员将数据存入数据库中,传统JDBC代码太复杂了,Mybatis可以更方便操作持久化层,容易上手
技术没有高低之分,只有掌握技术的人有高低之分
优点:
<?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> <!-- mybatis环境--> <environments default="development"> <!-- 第一个环境,id处也可以是default--> <environment id="development"> <!-- JDBC事务--> <transactionManager type="JDBC"/> <!-- 连接数据库配置--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/zh1z3ven/mapper/UserMapper.xml"/> </mappers> </configuration>
注册Mapper的小tips
可以借助*实现匹配所有Mapper.xml
<mappers> <mapper resource="com/zh1z3ven/mapper/*Mapper.xml"/> </mappers>
因为上面说到了SqlSession实例对象才可以进行对于数据库的操作,这里封装了这个获取sqlSession的步骤
主要是通过:SqlSessionFactoryBuilder > SqlSessionFactory> SqlSession实例==>执行sql语句,操作数据库
//SqlSessionFactoryBuilder ==> SqlSessionFactory //SqlSessionFactory ==> SqlSession实例 //sqlSession可以执行sql语句,操作数据库 public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; //从xml配置生成SqlSessionFactory实例 static{ try { String resource = "mybatis-config.xml"; InputStream inputStream = null; inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //获取sqlSession,操作数据库 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
这里利用Mapper接口和Mapper.xml配置文件替代了原先的Dao+实现类的操作。
public interface UserMapper { public List<User> getUserList(); }
可以将Mapper.xml看作是Mapper接口的实现类
namespace
绑定dao
层接口:namespace="com.zh1z3ven.mapper.UserMapper"
id
指定此标签中的sql语句对应于dao层接口的哪个方法:id="getUserList"
resultType
设置返回值类型,此处返回的User
类型的对象resultType="com.zh1z3ven.pojo.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"> <mapper namespace="com.zh1z3ven.mapper.UserMapper"> <select id="getUserList" resultType="com.zh1z3ven.pojo.User"> select * from user </select> </mapper>
获取sqlSession对象
String resource = "mybatis-config.xml"; InputStream resourceAsStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession();
封装成工具类
MybatisUtils
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml"; InputStream inputStream = null; inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
sqlSession.getMapper(UserMapper.class);
public class test { @Test public void testSql(){ //获取sqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //sqlSession.getMapper()执行SQL //调用实现类的getUserList方法 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.getUserList(); //遍历输出 for (User user : userList) { System.out.println(user); } //关闭资源 sqlSession.close(); } }
sqlSession.selectList("com.zh1z3ven.mapper.UserMapper.getUserList");
public class test { @Test public void testSql(){ //获取sqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //sqlSession.select("com.zh1z3ven.UserMapper.getUserList") 执行sql List<User> userList = sqlSession.selectList("com.zh1z3ven.mapper.UserMapper.getUserList"); //遍历输出 for (User user : userList) { System.out.println(user); } //关闭资源 sqlSession.close(); } }
增删改操作需要提交事务才可以完成
UserMapper
int addUser(User user);
UserMapper.xml
<!-- 对象中的属性可以直接取出来--> <insert id="addUser" parameterType="com.zh1z3ven.pojo.User"> insert mybatis.user(id, name , pwd) values(#{id}, #{name}, #{pwd}) </insert>
testAddUser
@Test public void testAddUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int i = mapper.addUser(new User(4, "ago", "123321")); if (i>0){ System.out.println("Add User Success"); } //提交事务 sqlSession.commit(); sqlSession.close(); }
UserMapper
int updateUser(User user);
UserMapper.xml
<update id="updateUser" parameterType="com.zh1z3ven.pojo.User"> update mybatis.user set pwd = #{pwd} where id = #{id} and name = #{name} </update>
testUpdateUser()
//修改user @Test public void testUpdateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int i = mapper.updateUser(new User(4, "ago", "123123")); if (i>0){ System.out.println("Update User Success"); } sqlSession.commit(); sqlSession.close(); }
UserMapper
int delUser(User user);
UserMapper.xml
<delete id="delUser" parameterType="com.zh1z3ven.pojo.User"> delete from mybatis.user where id = #{id} and name = #{name} and pwd = #{pwd} </delete>
testDeleteUser()
@Test public void testDeleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int i = mapper.delUser(new User(4, "ago", "123123")); if (i>0){ System.out.println("Delete User Success"); } sqlSession.commit(); sqlSession.close(); }
当数据库需要操作的表的字段或者xml中sql语句需要传入的参数过多时可以考虑用Map传递参数
UserMapper
int addUser2(Map<String,Object> map);
UserMapper.xml
<insert id="addUser2" parameterType="map"> insert mybatis.user(id, name, pwd) values(#{userId}, #{userName}, #{userPassword}) </insert>
test
@Test public void addUser2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String, Object> map = new HashMap<String, Object>(); map.put("userId", 6); map.put("userName", "zh1z3ven"); map.put("userPassword", "12344321"); int i = mapper.addUser2(map); if (i>0){ System.out.println("Add User With Map Success"); } sqlSession.commit(); sqlSession.close(); }
模糊查询时需要使用到通配符%,一般放在java代码里
UserMapper
List<User> getUserLike(String value);
UserMapper.xml
<select id="getUserLike" resultType="com.zh1z3ven.pojo.User"> select * from user where name like #{value} </select>
test
@Test public void testGetUserLike(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> map = new HashMap<String, Object>(); map.put("value", "li"); List<User> userList = mapper.getUserLike("%li%"); for (User user : userList) { System.out.println(user); } sqlSession.close(); }
mybatis可以适应多种环境,但是SqlSession只能一次用于一种环境
一般通过id属性来配置sql环境
通过default属性选择要使用的sql环境
<environments default="development">
transactionManager(事务管理器)有两种事务管理器JDBC和MANAGED,一般用JDBC可以提交事务和事务回滚。
<transactionManager type="JDBC"/>
dataSource(数据源)用于连接数据库,默认为POOLED,有池的连接
<dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource>
通过配置属性来引用配置文件
之前是像下面一样直接把连接数据库所需的driver url 等写死的,也可以不写死
<property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT-8"/> <property name="username" value="root"/> <property name="password" value="123456"/>
通过properties引入外部配置文件
<properties resource="db.properties"> </properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments>
设置返回类型的别名。只和xml有关,用来减少完全限定名的冗余。
通过指定一个类来给起短名
<typeAliases> <typeAlias type="com.zh1z3ven.pojo.User" alias="User"/> </typeAliases>
通过扫描package来指定JavaBean
在没有注解的情况下会使用JavaBean的小写名来当作别名
<typeAliases> <package name="com.zh1z3ven.pojo"/> </typeAliases>
使用注解形式起别名(在使用扫描package的情况下)
@Alias("类名")
logImpl => 指定日志实现
方式一:通过指定资源文件xml注册
<mappers> <mapper resource="com/zh1z3ven/mapper/UserMapper.xml"/> </mappers>
方式二:通过class指定映射
<mappers> <mapper class="com.zh1z3ven.mapper.UserMapper"/> </mappers>
方式三:使用package
<mappers> <package name="com.zh1z3ven.mapper.UserMapper"/> </mappers>
解决属性名和字段名不一致的问题
将数据表中的列与实体类中的属性对应上
UserMapper.xml
<resultMap id="" type="UserMap"> <result column="id" property="id"/> <!--column对应数据表中字段,property对应javabean中属性--> <result column="name" property="username"/> <result column="pwd" property="password"/> </resultMap> <!--指定resultMap名字为UserMap--> <select id="getUserList" resultMap="UserMap"> select * from user </select>
在mybatis核心配置文件中添加如下:
<settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
Log4j是Apache的开源项目,Log4j可以控制日志输出的地方为控制台、GUI组件、文件等;可以设置输出日志的等级;只需要操作配置文件即可,无需改动代码。
Log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/kuang.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
在mybatis核心文件中配置log4j
mybatis-config.xml
<settings> <setting name="logImpl" value="LOG4J"/> </settings>
简单使用
//设置log为当前类 static Logger logger = Logger.getLogger(test.class); @Test public void testLog4j(){ //设置log级别 logger.info("info:进入了Log4j"); logger.debug("debug:进入了Log4j"); logger.error("error:进入了Log4j"); }
public void testSql(){ //获取sqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); logger.info("info:获取SqlSession对象成功"); List<User> userList = sqlSession.selectList("com.zh1z3ven.mapper.UserMapper.getUserList"); //遍历输出 for (User user : userList) { logger.info("info:用户:" + user); } //关闭资源 sqlSession.close(); logger.info("info:关闭资源"); }
之前提到的都是用Mapper映射xml实现的sql语句操作数据库,sql语句主要是写到了xml文件中,Mybatis还提供了注解实现sql语句操作数据库,更加简化了代码编写。但是如果是更复杂的sql,还是需要用xml来编写,注解的方式只适合一些简单的sql语句。
mybatis-config.xml 绑定接口(注意用注解绑定的就是接口,)
<mappers> <mapper class="com.zh1z3ven.mapper.UserMapper"></mapper> </mappers>
UserMapper
public interface UserMapper { //查询所有用户 @Select("select * from user") List<User> getUserList(); }
test
static Logger logger = Logger.getLogger(test.class); @Test public void testGetUserList(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.getUserList(); for (User user : userList) { logger.info("info:"+user); } sqlSession.close(); }
在mybatis-config.xml注册Mapper(这里不能像xml可以用*匹配所有,需要一个一个注册)
<mappers> <mapper class="com.zh1z3ven.mapper.UserMapper"></mapper> </mappers>
接口
//查询所有用户 @Select("select * from user") List<User> getUserList(); //根据id查询用户,利用@param注解传参 @Select("select * from user where id = #{id}") User getUserById(@Param("id") int id); //add user @Insert("insert into user (id, name, pwd) values (#{id}, #{username}, #{password})") int addUser(Map map); //update user @Update("update user set name=#{username},pwd=#{password} where id = #{id}") int updateUser(User user); //delete user @Delete("delete from user where id = #{id}") int deleteUser(@Param("id") int id);
关于@Param注解
关于#{}与${}
动态SQL:利用Mybatis中自带的标签,根据不同的条件生成不同的SQL语句。
简单来说,我们之前利用JDBC写dao层的时候,是没有办法处理sql语句逻辑的,处理逻辑只能在上层实现,那么就造成了可能需要写很多的sql,而动态sql可以帮助我们在mybatis中实现部分的逻辑处理,简化一部分的开发。
在Mybatis中有4种标签
if choose(when, otherwise) trim(where, set) foreach
类似于java中if else语句
<select id="StudentMapper" parameterType="Map" resultMap="Student"> select * from user where <if test="id != null!"> id = #{id} </if> </select>
trim标签可以定制where元素的一些功能, trim标签有几个属性值。
prefix="" prefixOverrides="" suffix="" suffixOverrides=""
移除指定在prefixOverrides的内容并且插入prefix中指定的内容
当然如果类似于上面if标签那样拼接语句时如果有多个条件的情况下,还是形容上面那样写可能就会报错,例如
<select id="StudentMapper" parameterType="Map" resultMap="Student"> select * from user where <if test="id != null!"> id = #{id} </if> <if test="id != null!"> and name = #{name} </if> </select>
如果此时之匹配到了name条件的话,sql就会变成
select * from user where and name = xxx;
这样是会出现bug的,正常逻辑应该是如果只匹配到了name参数但是他的sql语句中有and关键字,那么需要去除掉这个and。
而where标签就很好的解决了这个事情:将原sql中的where去掉,改用where标签代替即可
<select id="StudentMapper" parameterType="Map" resultMap="Student"> select * from user <where> <if test="id != null!"> id = #{id} </if> <if test="name != null!"> and name = #{name} </if> </where> </select>
set 元素可以用于动态包含需要更新的列,忽略其它不更新的列;
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
可以配合if或者choose来筛选需要更新的列
<update id="updateAuthorIfNecessary"> update Author <set> <if test="username != null">username=#{username},</if> <if test="password != null">password=#{password},</if> <if test="email != null">email=#{email},</if> <if test="bio != null">bio=#{bio}</if> </set> where id=#{id} </update>
类似于java中swtich case语句,满足when标签中的表达式,则执行该when中的sql语句,若都不满足则执行otherwise中的sql语句
<select id="StudentMapper" parameterType="Map" resultMap="Student"> select * from user <where> <choose> <when test="id != null!"> id = #{id} </when> <when test="name != null!"> and name = #{name} </when> <otherwise> and 1=1 </otherwise> </choose> </where> </select>