#mybatis介绍#
支持普通SQL查存过程和高级映射的优秀持久层框架。消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。
使用简单的XML或注解用于配置和原始映射,将接口和 Java 的普通对象映射成数据库中的记录。
实现了DAO接口与xml映射文件的绑定,自动为我们生成接口的具体实现,使用起来变得更加省事和方便。
<!--优点-->
把Sql语句从Java中独立出来。
封装了底层的JDBC,API的调用,并且能够将结果集自动转换成JavaBean对象,简化了Java数据库编程的重复工作。
自己编写Sql语句,更加的灵活。入参无需用对象封装(或者map封装),使用@Param注解
Ibatis的升级版本。
(2010年,apache的Ibatis框架停止更新,并移交给了google团队,同时更名为MyBatis。
从2010年后Ibatis在没更新过,彻底变成了一个孤儿框架。一个没人维护的框架注定被mybatis拍在沙滩上。)
#核心#
SqlSession
#原理#
通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory。
SqlSessionFactory开启一个SqlSession,通过SqlSession实例获得Mapper对象并且运行Mapper映射的Sql语句。
完成数据库的CRUD操作和事务提交,关闭SqlSession。
#使用模式#
1,注解使用情况:Sql语句简单时直接写在Dao层
@Mapper
public interface TestDao {
@Select("select id, name, name_pinyin from mm_test; ")
List<MmTest> selectAll();
@Insert("insert into mm_test(id, name) values(#{id}, #{name})")
public void insertUser(MmTest mmtTestS);
}
2,xml绑定使用情况:xml绑定 (@RequestMap用来绑定xml文件)
(id名与dao层方法名一致)
<select id="">
${}:预编译处理,把${}直接替换成变量的值,不做任何转换。
#{}:字符串替换,sql中的#{}替换成?,有效的防止Sql语句注入。
总结:一般用#{}来进行列的代替
#实体类#
#工具类#
public class MyBatisUtil {
private static SqlSessionFactory factory;
static{
//1.获取mybatis.xml的输入流
InputStream iStream;
try {
iStream=Resources.getResourceAsStream("Mybatis-config.xml");
factory=new SqlSessionFactoryBuilder().build(iStream);
} catch (Exception e) {
// TODO: handle exception
}
}
public static SqlSession createSqlSession(){
//取消自动提交
return factory.openSession(false);
}
public static void closeSqlsession(SqlSession session){
if (session!=null) {
session.close();
}
}
}
#接口#
/**
* 根据用户姓名来进行模糊查询
*/
public List<User> getUserListByUserName(String username);
public List<User> getUserListByMap(Map<String, String> usermap);
#测试#
@Test
public void getUserListByUserName(){
SqlSession sqlSession = null;
List<User> userList = new ArrayList<User>();
try {
sqlSession = MyBatisUtil.createSqlSession();
//第一种方式:调用selectList方法执行查询操作
//userList = sqlSession.selectList("cn.smbms.dao.user.UserMapper.getUserList");
//第二种方式:调用getMapper(Mapper.class)执行dao接口方法来实现对数据库的查询操作
userList = sqlSession.getMapper(UserMapper.class).getUserListByUserName("赵");
(关闭自动提交后,增删改执行后 需要自己提交)
// sqlsession.commit();
} catch (Exception e) {
// TODO: handle exception
(增删改执行后 执行失败后回滚)
//sqlsession.rollback();
e.printStackTrace();
}finally{
MyBatisUtil.closeSqlSession(sqlSession);
}
for(User user: userList){
logger.debug("testGetUserList userCode: " + user.getUserCode() + " and userName: " + user.getUserName());
}
}
@Test
public void getUserListByMap(){
SqlSession sqlSession = null;
List<User> userList = new ArrayList<User>();
try {
sqlSession = MyBatisUtil.createSqlSession();
Map<String, String>usermap=new HashMap<String, String>();
usermap.put("username", "赵");
usermap.put("userRole", "2");
userList = sqlSession.getMapper(UserMapper.class).getUserListByMap(usermap);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
MyBatisUtil.closeSqlSession(sqlSession);
}
for(User user: userList){
logger.debug("testGetUserList userCode: " + user.getUserCode() + " and userName: " + user.getUserName());
}
}
#XML代码#【XML需要与Dao接口名一致,通过session.getMapper(接口名.class).方法名(参数)调用执行】
直接复制使用(使用前要手动配置文件)
<?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的路径)
<mapper namespace="Dao.UserMapper">
//返回类型1
<resultMap type="Pojo.User" id="User">
(同字段名自动匹配)
<result property="ID" column="ID"/>
(一对一:加了一个类)
<association property="role" javaType="Pojo.Role">
<id property="id" column="id"/>
<result property="roleName" column="roleName"/>
</association>
</resultMap>
//返回类型2
<resultMap type="Pojo.User" id="User1">
<result property="ID" column="ID"/>
(一对多:加了一个集合或者map)
<collection property="addressList" ofType="Pojo.Address">
<result property="id" column="id"/>
</collection>
</resultMap>
<!-- 1对1嵌套查询 -->
【下面代码在接口中实现使用@param("id")注入参数,如果没有使用则为后面()中代码,使用更新操作则<update></update>,其他同理】
<select id="Select1" resultMap="User">
SELECT a.*,b.roleCode FROM smbms.smbms_user a ,smbms_role b WHERE a.userRole=b.id AND a.userRole=#{id}
</select>
<!-- 1对多嵌套查询 -->
<select id="Select2" resultMap="User1" >
SELECT a.*,b.addressDesc,b.contact FROM smbms.smbms_user a ,smbms_address b WHERE a.id=b.userId AND b.id=#{id}
</select>
<select id="Modif" resultMap="User1" >
</select>
(<select id="getUserListByUserName" resultType="User" parameterType="String">
SELECT * FROM smbms_user WHERE userName LIKE CONCAT ('%',#{username},'%')
</select>
<select id="getUserListByMap" resultType="User" parameterType="Map">
SELECT * FROM smbms_user WHERE userName LIKE CONCAT ('%',#{username},'%')
and userRole=#{userRole}
</select>)
</mapper>
#条件查询的xml#
<mapper namespace="Dao.BillMapper">
<resultMap type="Pojo.Bill" id="Map1">
<result property="id " column="id "/>
</resultMap>
(单一条件使用<choose> <when></when></choose>)
<select id="Select" resultMap="Map1" parameterType="Map">
SELECT a.*,b.proName FROM smbms.smbms_bill a ,smbms_provider b WHERE a.providerId=b.id
<if test="name!=null and name!=''"> and productName like concat('%',#{name},'%') </if>
<if test="id!=null"> and providerId=#{id} </if>
<if test="flag!=null"> and isPayment=#{flag} </if>
</select>
<update id="Modif" parameterType="Pojo.Bill" >
UPDATE smbms.smbms_bill a
(前缀后缀及忽略设置)
<trim prefix="set" suffix="where a.id=#{id}" suffixOverrides=",">
<if test="billCode!=null">a.billCode=#{billCode},</if>
<if test="productName!=null">a.productName=#{productName},</if>
<if test="productDesc!=null">a.productDesc=#{productDesc},</if>
<if test="productUnit!=null">a.productUnit=#{productUnit},</if>
<if test="productCount!=null">a.productCount=#{productCount},</if>
<if test="totalPrice!=null">a.totalPrice=#{totalPrice},</if>
<if test="isPayment!=null">a.isPayment=#{isPayment},</if>
<if test="createdBy!=null">a.createdBy=#{createdBy},</if>
<if test="creationDate!=null">a.creationDate=#{creationDate},</if>
<if test="modifyBy!=null">a.modifyBy=#{modifyBy},</if>
<if test="modifyDate!=null">a.modifyDate=#{modifyDate},</if>
<if test="providerId!=null">a.providerId=#{providerId},</if>
</trim>
</update>
(通过传入的数组或list或map【map里放字符和list】获取条件,进行查询)
<select id="Select1" resultMap="Map1" >
SELECT a.*,b.proName FROM smbms.smbms_bill a ,smbms_provider b WHERE
a.providerId=b.id and a.id in
(循环遍历)
<foreach collection="Array" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</select>
<select id="Select2" resultMap="Map1" >
SELECT a.*,b.proName FROM smbms.smbms_bill a ,smbms_provider b WHERE
a.providerId=b.id and a.id in
<foreach collection="List" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</select>
<select id="Select3" resultMap="Map1" >
SELECT a.*,b.proName FROM smbms.smbms_bill a ,smbms_provider b WHERE
a.providerId=b.id
AND a.isPayment=#{isPa}
AND a.id IN
<foreach collection="List" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</select>
</mapper>
#mybatis的配置XML代码#【一般放在src/resource内,有配置文件database.properties和日志文件log4j.properties】
直接复制使用
<?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 resource="database.properties"/>
<!-- 配置mybatils的log实现 -->
<settings>
<setting name="logImpl" value="LOG4J"/>
<!-- 自动配备全开(字段名匹配,同名),联表查询则需要开启(只用设置不同名,其他同名自动匹配)。 -->
<setting name="autoMappingBehavior" value="FULL"/>
</settings>
(自动扫描,使前面与接口同名的xml内引入文件名可以少打一些共有代码)
<typeAliases>
<package name="Pojo"/>
</typeAliases>
<!-- default默认 -->
<environments default="development">
<environment id="development" >
<!-- 配置事务JDBC的事务管理 -->
<transactionManager type="JDBC"/>
<!-- tomcat数据源 -->
<dataSource type="POOLED" >
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${name}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
(引入接口的xml)
<mappers>
<mapper resource="Dao/UserMapper.xml"/>
<mapper resource="Dao/BillMapper.xml"/>
</mappers>
</configuration>
#复习#
1. 查询 select标签
2. resultType一般用来返回的是对象,但是可能有点情况下数据库和实体类当中的表字段不一致的情况,那我们需要使用resultmap----源于我们的map集合
3. 修改、新增、删除 传入参数-----如果有多个参数,那么在我们的xml当中是无法去判断参数的,所以我们需要使用注解来帮助我们指定我们传入的是什么参数
4. mybatis执行的增删改也有返回值,同时需要注意的是,我们创建的时候默认的是不自动提交,当我们执行成功之后就需要提交commit
5. sqlsession的生命周期---存在于一次请求,由于我们是默认的不自动提交,所以我们可以在里面执行多次sql。原理:由于sqlsession是由我们的SqlSessionFactory创建的,他是一个人力劳动市场,sqlsession相当于是一次人力,sqlsession这一次生命周期中执行多个语句都是可以的,但是当我们关闭了sqlsession之后,将无法再次使用。
6. 一对一 就是左表和右表都有相关联的数据,并且有且仅有一条记录关联,在这个时候,虽然我们可以使用之前的resultmap方式,在对象当中新增一些字段,但是这样不方便后期维护。我们为了方便后期维护,就是用了一对一的方式。在对象当中嵌套一个关联的对象。
<resultMap type="User" id="userRoleResult">
<result property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
<result property="phone" column="phone"/>
<result property="birthday" column="birthday"/>
<result property="gender" column="gender"/>
<result property="userRole" column="userRole"/>
<association property="role" javaType="Role" resultMap="roleresult">
</association>
</resultMap>
<resultMap type="Role" id="roleresult">
<id property="id" column="id"/>
<result property="roleName" column="roleName"/>
<result property="roleCode" column="roleCode"/>
</resultMap>
7. 可能将来会遇到一个用户有多个地址的情况---一对多
8. 比如我们在京东上面购物,我这个账号有多个地址,查地址呗。但是有很多公司的后台,需要通过人名或者编号来查询这个帐号下面的地址
#什是项目核心?#
项目实现什么功能,用了什么技术,是在怎样的环境下开发的,工作周期
#得到了什么?#
刚开始的时候,由于我的代码还不够规范,所以总是出现很多bug,但是随着后面代码越来越熟练,
我也知道了代码规范的重要性,并且知道了如何去定位BUG,解决BUG。