MyBatis

MyBatis

##1.什么是mybatis
mybatis是apache的一个开源项目,他是一个优秀的持久层框架,他对jdbc的操作数据库的过程及逆行封装,使开发者只需关注SQL本身,而不需要去处理注册驱动、创建connection、创建statement、手动设置参数、结果集检索等。

MyBatis通过xml或注解的方式将要执行的各种statement(传输入)(statement、preparedStatement)配置起来,通过java对象和statement中的sql进行映射生成最终的sql语句,最后由mybatis框架执行sql并将结果映射成java对象返回。

总之,就是对jdbc访问数据库的过程进行了封装,简化了jdbc代码,解决了jdbc将结果封装为java对象的麻烦。

###回顾JDBC进行查询,并返回结果集

  1. 利用反射来注册驱动

    Class.forName("com.mysql.jdbc.Driver");
  2. 获取连接对象三个参数,url(库路径),username(用户名),password(密码)

    conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/EMP?characterEncoding=utf-8","root","123456");
  3. 获取传输器

    stat=conn.createStatement();
  4. 执行sql语句,并返回执行的结果

    String sql="select * from emp";

    rs=stat.executeQuery(sql);
  5. 处理结果集

    > //创建list集合
  List<Emplist=new ArrayList<Emp>();
  //用rs.next() 来判断是否有下一行
  while(rs.next()) {
  	//将每一条记录封装成集合
  	Emp emp=new Emp();
  	//要把表记录中第一行取出来设置为emp中的id属性
  	emp.setId(rs.getInt("id"));
  	emp.setName(rs.getString("name"));
  	emp.setJob(rs.getString("job"));
  	emp.setSalary(rs.getDouble("salary"));
  	list.add(emp);
  }
  return list; 

6.释放资源

//释放资源的方法
	public static void cloose(Connection conn,Statement stat,ResultSet rs) {
		/*
		 * 	判断三个对象是否为空,如果不为空,则进行关闭,并设置为空
		 */
		if(rs!=null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}finally {
				rs=null;
			}
		}
		if(stat!=null) {
			try {
				stat.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}finally {
				stat=null;
			}
		}
		if(conn!=null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}finally {
				conn=null;
			}
		}
	}
}

#####当然我们可以将程序放入servlet中,在本地服务器上运行,在WEB-INF下添加emp.jsp,用表格的方式显示出来。在EmpServlet类中写
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
//接收请求方式。接收字节流
response.setContentType(“text/html;charset=utf-8”);
PrintWriter out = response.getWriter();
//通过out的方法向外写数据
//调用TestJdbc的findAll方法,查询所有员工的信息
List<Emplist=TestJdbc.findAll();
//将员工集合存入request域中
request.setAttribute(“list”, list);
//通过转发,将员工集合带到index.jsp遍历取出显示
request.getRequestDispatcher(“index.jsp”).forward(request, response);
}
emp.jsp,也可以设置表格属性

<!-- 想从域中取数据,并遍历 需要jstl -->
<h3>遍历员工集合</h3>
<table>
	<c:forEach items="${list }" var="emp">
		<tr>
			<td>${emp.id}</td>
			<td>${emp.name}</td>
			<td>${emp.job}</td>
			<td>${emp.salary}</td>
		</tr>
</c:forEach>
</table>

访问EmpServlet,启动tomcat,打印员工信息表

JDBC的缺点,为啥要mybatis

  1. 用JDBC对数据库操作效率低,重复代码太多,(注册驱动,获取连接等),但是mybatis可以简化JDBC代码。

  2. JDBC自身并没有什么连接池,会频繁的创建和连接和关闭,导致程序效率更低了。mybatis自身支持连接池,可以提高效率。

  3. JDBC的SQL语句都是写死的,每一次改动,都会重新编译。mybatsi是将SQL配置在xml文件中,修改sql只需要修改配置文件,不需要重新再编译。

  4. JDBC执行h后返回的结果集合需要我们手动处理,不叫繁琐。mybatis对查询SQL执行后返回的的ResultSet对象,会帮我们自动处理转为Java对象。
    ##写一个简单MyBatis项目

  5. 创建maven工程

  6. 配置pom文件(导入:mysql驱动包,mybatis整合包,junit单元测试包,slf4j-log4j12日志包)

  7. 创建一个测试类TestMybatis,提供一个findAll方法,写一个测试单元方法。

  8. 在resources下配置两个xml文件,mybatis-config.xml(mybatis的核心配置文件)和EmpMapper.xml(映射),所有的关于Emp表的sql语句都在映射中。

  9. 配置mybatis-config.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">
         
     <!-- MyBatis的全局配置文件 -->
     <configuration >
     	
     </configuration>
    
  10. 配置EmpMapper.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一般指定为当前文件的所在包路径+文件名
     		将来在程序中通过[ namespace + id ]定位到执行哪一条SQL语句
     	 -->
     	<mapper namespace="com.tedu.pojo.EmpMapper">
     		<!-- 通过select、insert、update、delete标签声明要执行的SQL -->
     		<select id="findAll" resultType="com.tedu.pojo.Emp">
     			select * from emp
     		</select>
     		<!-- 
     		resultType:返回值类型,简单类型(例如:Integer,String,Emp等)
     			如果返回集合(List<Emp>),只需配置集合中的元素类型即可!
     		resultMap:复杂对象结构(例如多表关联查询等),后面用到再讲解
     		 -->
     	</mapper>
    
  11. 在mybatis-config.xml中引入EmpMapper.xml 文件,按住shift是否能跳转到EmpMapper.xml中

     <!-- 2.导入mapper.xml文件(其中包含了我们要执行的sql语句) -->
     <mappers>
     <!-- resource指为源码的目录 -->
     <mapper resource="EmpMapper.xml"/>
     </mappers>
    
  12. 配置mybatis-config.xml文件
    ##配置开发环境

org.apache.ibatis.exceptions.PersistenceException:

Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for EmpMapper.findAll

Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for EmpMapper.findAll

at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:26)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:111)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:98)
at com.yjq.mybatis.TestMybatis.findAll(TestMybatis.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for EmpMapper.findAll
at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:797)
at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:631)
at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:624)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:107)
... 26 more

这个错误的原因集合里面不包含id或者值,有问题,检查你的namespce或者id的是否是一致的

###2.mybaitsi执行的过程

  1. 配置好Mapper.xml文件和mybatis-config.xml文件

  2. 创建普通java类对象,并提供set和get方法

     //生成对应的get和set方法
     private Integer id;
     private String name;
     private String job;
     private Double salary;
     public Integer getId() {
     	return id;
     }
     public void setId(Integer id) {
     	this.id = id;
     }
     public String getName() {
     	return name;
    
  3. 创建TestMybatis类,进行增删改查的测试

     public void findAll() throws IOException {
     	//1.读取mybatis的核心配置文件(mybatis-config)
     	InputStream in=Resources.getResourceAsStream("mybatis-config.xml");
     	//2.通过配置获取一个SqlSessionFactory,sqlsession工厂,他是用来生成SqlSession对象的
     	SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
     	//3.通过工厂获取袷SqlSession对象,类似于JDBC的Connection,它可以获取对象,处理,并返回结果
     	SqlSession session = factory.openSession();
     	//4.执行SQL语句(namespace+id)
     	List<Emp> selectList = session.selectList("EmpMapper.findAll");
     	//返回一个List<Emp> empList=...
     	//5.输出结果
     	for (Emp emp : selectList) {
     		System.out.println(emp);
     	}
    
  4. 在EmpMapper.xml中写我们的Sql语句

  <mapper namespace="EmpMapper">
	<!-- 通过select、insert、update、delete标签声明要执行的SQL -->
	<select id="findAll" resultType="com.yjq.pojo.Emp">
		select * from emp;
	</select>
	<!-- 
	resultType:返回值类型,简单类型(例如:Integer,String,Emp等)
		如果返回集合(List<Emp>),只需配置集合中的元素类型即可!
	resultMap:复杂对象结构(例如多表关联查询等),后面用到再讲解
	 -->
	 <!-- 一般我们不会在增删改上指定 resultType,因为他们返回的是int类型的,
	 (也就是影响的结果行数),但是每个sql语句的id值不能相同,指定的类型就是该表的类型-->
	 <insert id="insert">
	 	insert into emp values(null,'张三','高级java开发工程师',35000);
	 </insert>

###这里一定要将数据库连接,并保证有正确的库
##注意:
1.namespace一般指定为当前文件的所在包路径加文件名,程序通过namespcae+id可以定位到指定的Sql语句。
2.EmpMapper.xml中sql语句的id必须和TestMybatis类中的执行sql语句中的id一致

selectList("EmpMapper.findAll");
<select id="findAll" resultType="com.yjq.pojo.Emp">

###3.为了解决我们不把sql语句写死,换的灵活点,引用了占位符,
JDBC的占位符为?
MyBatis的占位符为#{属性名},属性名就是表中的属性列名

  1. 如果我们需要传入的值比较多,但是执行sql语句的只能有两个参数

     int row = session.insert("EmpMapper.insert"," ");
    
  2. 那如何解决多个传入的参数,我们可以将参数进行封装,然后再传入,把封装后的对象再传入,可以用该表类型封装,也可以用map集合。
    ######先用Emp表进行封装

    public void testUpdate() {
    //创建Emp对象,对参数进行封装
    Emp e=new Emp();
    e.setId(5);
    e.setName(“杭州马”);
    e.setJob(“AliabaaCEO”);
    e.setSalary(3431000000000d);
    int row = session.update(“EmpMapper.updateById”,e);
    //提交事务,不然会回滚
    session.commit();
    System.out.println(row);
    }
    ########现在来替换要更改的信息

    update emp set name=#{name},job=#{job},salary=#{salary} where id=#{id};

#####用Map集合来传参数
//用map集合来传参数
//1.创建map集合,并用V put(K key, V value) 将指定的值与此映射中的指定键关联 ,用put方法进行存入数据
Map map=new HashMap();
map.put(“id”, 4);
map.put(“name”, “深圳腾”);
map.put(“job”, “TecentCEO”);
map.put(“salary”, 1200000d);
//传入map
int rows = session.update(“EmpMapper.updateById”,map);
session.commit();
System.out.println(rows);
###关于传入的参数,占位符必须中变量名要与属性名保持一致,并且我们优先考虑用类对象进行封装,其次考虑map集合封装。

#{}和${}这是两个占位符

${} 这个是js中的占位符
#{}

####需要注意,再传递KaTeX parse error: Expected 'EOF', got '#' at position 38: …*总结:在大多数情况下还是使用#̲{}占位符,而{}多用于不带引号的字符进行占位**
##4动态SQL (if ,where)
(1) mybatis中的if元素用于对某一字段进行判断,比如根据判断过来的参数是否为空,从而决定是否执行包含在其中的SQL片段。
(2)where元素则用于对包含在其中的SQL语句进行检索,需要时剔除多余的连接词,比如(and或者or),并且需要时可以添加where关键字。
**(3)在mybatis中的set元素用用于对包含在其中的sql语句进行检索,在需要时可与剔除其中多余的连接符(比如逗号),并且在需要时可以添加set关键字 **
ps:

@Test
public void testFindAll4(){
    Emp emp=new Emp();
    emp.setId(4);
    emp.setName("呆鸡贵");
    emp.setJob("掏粪大队队长");
    emp.setSalary(25000d);
    //执行sql语句
    int rows = session.update("EmpMapper.testFind4",emp);
    //提交
    session.commit();
    System.out.println("影响的行数:"+rows);

添加后set
<update id="testFind4">
    update emp
    <set>
        <if test="name!=null">
            name=#{name},
        </if>
        <if test="job!=null">
            job=#{job},
        </if>
        <if test="salary!=null">
            salary=#{salary}
        </if>
    </set>
    where id=#{id}
</update>

(4)通过forEach标签来批量删除

测试类

//练习:如何通过id进行批量删除
@Test
public  void  testDelete(){
    //进行需要删除的id序号
    Integer[] num={1,2,3,8,11};
    //执行sql语句
    int rows = session.update("EmpMapper.testDelete", num);
    //提交事务
    session.commit();
    System.out.println("影响的行数:"+rows);
}

类对应的xml中的sql语句

<!--通过id进行批量删除
    1.delete from emp where in(1,2,4,5,6,9);
    2.delete from emp where id=1 or id=2 or id=3...
    引进forEach标签,里面有四个属性: collection=” “,如果要变数集合就是list,数组的话就是array
    open=” “,开始符号,(
    close=” “结束符号,)
    item=" ",接收遍历的结果
    separator=",",拼接符号:,
-->
<delete id="testDelete">
    delete from emp where id in
    <foreach collection="array" open="("  item="id" separator="," close=")">
        #{id}
    </foreach>
</delete>

##5 mybatis中的Mapper接口开发(为了解决)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值