精华内容
下载资源
问答
  • Mybatis框架学习

    2020-12-28 13:08:13
    数据持久化5、Mybatis框架使用-xml方式16、Xml方式1-CRUD操作7、配置日志8、Mybatis框架使用-xml方式29、mybatis.cfg.xml核心配置文件详细说明10、映射文件配置详解11、模糊查询12、分页查询13、动态sql14、mybatis...


    前言

    目前最主流的持久层框架为 hibernate 与 mybatis ,而且国内目前情况使用 Mybatis 的公司比 hibernate 要多。

    Hibernate的缺点:a、学习门槛不低,要精通门槛更高。门槛高在怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate缓存与数据加载策略方面。b、sql优化方面,Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。当然了,Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。说得更深入一些,如果有个查询要关联多张表,比如5张表,10张表时,而且,我们要取的字段只是其中几张表的部分字段。这时用hibernate时就会显得非常力不从心。就算用hibernate的sqlquery,后续的维护工作也会让人发狂。


    一、Mybatis是什么?

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

    二、Mybatis学习总结

    1.框架的底层实现技术-反射技术

    (1)概念
    我们之前使用的都是我们已知的类,每个类中有哪些属性、方法、构造器我们都很清楚,直接调用即可。我们都是在编译之前使用的。
    如果在运行时,突然给你一个类,我们是不知道这个类的内容的,需要先了解这个类的内容,然后才能使用。这个过程我们叫反射。
    反射,在程序运行时,我们对未知类的探索和使用过程。
    (2)类加载器
    JVM在执行程序之前,需要先加载类,使用类加载器加载。

    类加载器:
    核心类加载器-jdk/lib的java的核心jar包
    扩展类加载器-jdk/lib/ext的java的扩展jar包
    应用系统类加载器-我们项目引入的第三方jar包和我们写的class

    加载顺序:核心类加载器–>扩展类加载器–>应用系统类加载器

    加载使用“双亲委托模式”:
    首先,我们要运行程序,通过应用系统类加载器找到我们我们编写的类,交给扩展类加载器,然后扩展类加载器再交给核心类加载器。
    开始加载:核心类加载器先加载核心api,交给扩展类加载器继续加载扩展api,最后交给应用系统加载器加载剩下的api。
    如果这个类最后还没有加载,报ClassNotFoundException。
    (3)jvm内存分配
    JVM每加载一个类,都会创建一个Class对象,该对象中保存类的信息。Class对象在堆内存中。

    (4)反射:通过Class对象获取类的内容。

    代码如下:

    package com.entity;
    
    //未知的类
    public class Student {
    	private  int  a;
    	public   int  b;
    	
    	private  void  test1() {
    		System.out.println(11);
    	}
    	
    	public  void  test2() {
    		System.out.println(22);
    	}
    	
    	public Student() {
    		System.out.println("null");
    	}
    
    	private Student(Integer a, Integer b) {
    		super();
    		this.a = a;
    		this.b = b;
    	}
    	
    }
    
    
    //		反射:获取类的内容
    //		第一步,获取这个类对应的Class对象
    //		Class  stuCls=Student.class;
    		Class  stuCls=Class.forName("com.entity.Student");
    //		Student  s=new  Student();
    //		Class  stuCls=s.getClass();
    		
    //		第二步,通过Class对象,获取属性、方法、构造器
    //		获取构造器
    //		获取的公开的构造器
    		Constructor[]  cons=stuCls.getConstructors();
    //		获取所有的构造器
    		Constructor[]  consAll=stuCls.getDeclaredConstructors();
    //		System.out.println(cons.length);
    //		System.out.println(consAll.length);
    //		获取单个构造器
    		Constructor  nullCon=stuCls.getConstructor(null);
    		Constructor  con=stuCls.getConstructor(Integer.class,Integer.class);
    		
    //		获取方法:包括继承的
    //		获取的是公开的方法
    		Method[] methods = stuCls.getMethods();
    //		获取所有的方法
    		Method[] methodsAll = stuCls.getDeclaredMethods();
    //		获取单个方法
    		stuCls.getMethod("test1", null);
    		
    //		获取属性
    //		获取公开的属性
    		Field[] fields = stuCls.getFields();
    //		获取所有的属性
    		Field[] fieldsAll=stuCls.getDeclaredFields();
    //		获取单个属性
    		stuCls.getField("a");
    
    //		反射:使用类的内容
    //		使用构造器创建对象
    		Student  stu1=(Student)nullCon.newInstance();
    		System.out.println(stu1.b);
    		
    //		使用它的方法解决问题
    		test2.invoke(stu1,null);
    		
    //		使用它的属性保存数据
    		b.setInt(stu1, 13);
    		System.out.println(b.getInt(stu1));
    

    2.框架的底层实现技术-代理模式

    (1)理解
    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
    这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法

    (2)代理方式
    静态代理
    JDK动态代理
    Cglib动态代理
    https://www.cnblogs.com/leeego-123/p/10995975.html
    (3)静态代理

    代码如下:

    package com.proxy;
    
    public interface IUserDao {
        void save();
    }
    public class UserDao implements IUserDao {
        public void save() {
            System.out.println("----已经保存数据!----");
        }
    }
    
    package com.proxy;
    
    public class UserDaoProxy implements IUserDao{
    	//接收保存目标对象
        private IUserDao target;
        public UserDaoProxy(IUserDao target){
            this.target=target;
        }
    	@Override
    	public void save() {
    		System.out.println("代理增强1");
    		//原来的功能
    		target.save();
    		System.out.println("代理增强2");
    	}
    }
    
    package com.proxy;
    
    public class TestStaticProxy {
    
    	public static void main(String[] args) {
    		IUserDao   old=new  UserDao();
    		IUserDao   proxy=new UserDaoProxy(old);
    
    		proxy.save();
    	}
    
    }
    
    

    (4)JDK动态代理

    package com.proxy.dyn;
    
    public interface IUserDao {
        void save();
    }
    
    package com.proxy.dyn;
    
    public class UserDao implements IUserDao {
        public void save() {
            System.out.println("----已经保存数据!----");
        }
    }
    
    package com.proxy.dyn;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyFactory {
    	//维护一个目标对象
        private Object target;
        public ProxyFactory(Object target){
            this.target=target;
        }
        
        //给目标对象生成代理对象
        public Object getProxyInstance(){
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("开始事务2");
                            //执行目标对象方法
                            Object returnValue = method.invoke(target, args);
                            System.out.println("提交事务2");
                            return returnValue;
                        }
                    }
            );
        }
    }
    
    package com.proxy.dyn;
    
    public class TestDynProxy {
    
    	public static void main(String[] args) {
    		IUserDao   target=new  UserDao();
    		ProxyFactory   factory=new  ProxyFactory(target);
    		IUserDao   proxy=(IUserDao)factory.getProxyInstance();
    		
    		proxy.save();
    	}
    
    }
    
    

    (5)Cglib动态代理
    asm-3.3.jar
    cglib-2.2.jar
    导入cglib的相关jar包,注意版本冲突。
    目标对象不需要实现接口。

    public class UserDao{
        public void save() {
            System.out.println("----已经保存数据!----");
        }
    }
    package com.proxy.cglib;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    /**
     * Cglib子类代理工厂
     * 对UserDao在内存中动态构建一个子类对象
     */
    public class ProxyFactory implements MethodInterceptor{
        //维护目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
            this.target = target;
        }
    
        //给目标对象创建一个代理对象
        public Object getProxyInstance(){
            //1.工具类
            Enhancer en = new Enhancer();
            //2.设置父类
            en.setSuperclass(target.getClass());
            //3.设置回调函数
            en.setCallback(this);
            //4.创建子类(代理对象)
            return en.create();
    
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("开始事务...");
    
            //执行目标对象的方法
            Object returnValue = method.invoke(target, args);
            
            System.out.println("提交事务...");
    
            return returnValue;
        }
    }
    
    package com.proxy.cglib;
    
    public class TestCglibProxy {
    	public static void main(String[] args) {
    		
    		UserDao   target=new  UserDao();
    		
    		ProxyFactory  factory=new  ProxyFactory(target);
    		UserDao  proxy=(UserDao)factory.getProxyInstance();
    		
    		proxy.save();
    	}
    }
    
    

    (6)spring aop
    spring aop 底层使用的是动态代理实现的。
    同时,支持两种动态代理。
    如果目标对象实现接口,采用jdk动态代理。
    如果目标对象没有实现接口,采用cglib动态代理。

    3.框架

    (1)使用的角度看:写好的很多jar包
    (2)框架是一个半成品,提供了一些基础功能的封装、统一编码结构。
    (3)我们java学的框架有:
    全方位框架–spring框架
    持久化框架–Mybatis框架、Hibernate框架、spring data jpa、jdbcTemplate
    MVC框架–Spring MVC框架、Struts2、Struts1

    4.数据持久化

    (1)解释
    数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称
    (2)我们一般使用数据库保存数据,我们主要做的是数据库的持久化操作。
    包含4项操作:增删改查。
    (3)jdbc
    (4)持久化框架
    Mybatis框架、Hibernate框架

    面试题:Mybatis框架和Hibernate框架有什么区别?
    在这里插入图片描述

    (5)Mybatis封装了jdbc,替换jdbc数据持久化操作。

    5、Mybatis框架使用-xml方式1

    (1)创建项目,下载和导入mybatis的jar包
    先导入数据库驱动包,然后导入mybatis核心包,还有mybatis的依赖包
    Mybatis3.5.6需要使用mysql-connector-8.x-java.jar连接数据库
    在这里插入图片描述
    (2)在src下创建核心配置文件mybatis.cfg.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>
    	<environments default="mysql">
    		<environment id="mysql">
    			<!-- 配置事务管理器,推荐JDBC事务管理器 ,还有一种使用容器的事务管理-->
    			<transactionManager type="JDBC"></transactionManager>
    			<!-- 数据源获取方式,推荐POOLED,还有UNPOOLED和JNDI -->
    			<dataSource type="POOLED">
    				<property name="driver" value="com.mysql.cj.jdbc.Drvier"/>
    				<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
    				<property name="username" value="root"/>
    				<property name="password" value="root"/>
    			</dataSource>
    		</environment>
    		<!-- <environment id="oracle">
    		</environment> -->
    	</environments>
    	
    	
    </configuration>  
    

    (3)创建com.mybatisTest.domain和实体类
    注意:属性名必须和列名相同,不区别大小写。

    package com.mybatisTest.domain;
    
    public class Users {
    	private  int  id;
    	private  String userName;
    	private  String pwd;
    	private  String  name;
    	private  String  tel;
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    	public String getPwd() {
    		return pwd;
    	}
    	public void setPwd(String pwd) {
    		this.pwd = pwd;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getTel() {
    		return tel;
    	}
    	public void setTel(String tel) {
    		this.tel = tel;
    	}
    	public Users() {
    		
    	}
    	private Users(int id, String userName, String pwd, String name, String tel) {
    		super();
    		this.id = id;
    		this.userName = userName;
    		this.pwd = pwd;
    		this.name = name;
    		this.tel = tel;
    	}
    	@Override
    	public String toString() {
    		return "Users [id=" + id + ", userName=" + userName + ", pwd=" + pwd + ", name=" + name + ", tel=" + tel + "]";
    	}
    	
    }
    
    

    (4)在src下创建一个包com.mybatisTest.mapper,在包下创建一个映射文件

    <?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.mybatisTest.mapper">
    	
    	<select id="findUserByUserName" parameterType="java.lang.String" resultType="com.mybatisTest.domain.Users">
    		select  *  from  users  where  username=#{value}
    	</select>
    
    </mapper>  
    

    (5)修改mybatis.cfg.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>
    	<environments default="mysql">
    		<environment id="mysql">
    			<!-- 配置事务管理器,推荐JDBC事务管理器 ,还有一种使用容器的事务管理-->
    			<transactionManager type="JDBC"></transactionManager>
    			<!-- 数据源获取方式,推荐POOLED,还有UNPOOLED和JNDI -->
    			<dataSource type="POOLED">
    				<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    				<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
    				<property name="username" value="root"/>
    				<property name="password" value="root"/>
    			</dataSource>
    		</environment>
    		<!-- <environment id="oracle">
    		</environment> -->
    	</environments>
    	
    	<mappers>
    		<mapper resource="com/mybatisTest/mapper/UsersMapper.xml"/>
    	</mappers>
    </configuration>  
    

    (6)获取连接,写个测试类

    package com.mybatisTest.test;
    
    import java.io.InputStream;
    
    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 com.mybatisTest.domain.Users;
    
    public class Test {
    
    	public static void main(String[] args) throws Exception {
    		String  xml="mybatis.cfg.xml";
    		InputStream  in=Resources.getResourceAsStream(xml);
    		
    		SqlSessionFactory  factory=new  SqlSessionFactoryBuilder().build(in);
    		SqlSession session=factory.openSession();
    		
    		Users  user = session.selectOne("com.mybatisTest.mapper.findUserByUserName","zhang3");
    		
    		System.out.println(user);
    		
    		session.close();
    	}
    
    }
    
    

    6、Xml方式1-CRUD操作

    (1)添加数据

    <insert id="addUser" parameterType="com.mybatisTest.domain.Users">
    		insert  into  users  values(null,#{userName},#{pwd},#{name},#{tel})
    	</insert>
    //		添加记录
    		Users  user=new  Users(2,"ziwei2","123456","ziwei","17810002000");
    		int i=session.insert("com.mybatisTest.mapper.addUser", user);
    		System.out.println(i);
    //		增删改需要提交,数据库才能生效
    		session.commit();
    

    (2)查询一条数据

    <select id="findUserById"  parameterType="java.lang.Integer" resultType="com.mybatisTest.domain.Users">
    		select  *  from  users  where  id=#{value}	
    	</select>
    Users  user = session.selectOne("com.mybatisTest.mapper.findUserById",8);
    		System.out.println(user);
    

    (3)查询多条数据

    <select id="findAllUser" resultType="com.mybatisTest.domain.Users">
    		select *  from  users
    	</select>
    List<Users>  list=session.selectList("com.mybatisTest.mapper.findAllUser");
    		for (Users users : list) {
    			System.out.println(users);
    		}
    

    (4)修改数据

    <update id="updateUserPwdById" parameterType="com.mybatisTest.domain.Users">
    		update  users  set  pwd=#{pwd}  where  id=#{id}
    	</update>
    //		修改
    		Users  user=new  Users(2,"ziwei2","6789","ziwei","17810002000");
    		session.update("com.mybatisTest.mapper.updateUserPwdById", user);
    

    (5)删除数据

    <delete id="deleteUserById" >
    		delete  from  users  where  id=#{value}
    	</delete>
    //		删除
    		session.delete("deleteUserById",1);
    

    7、配置日志

    (1)Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:
    SLF4J
    Apache Commons Logging
    Log4j 2
    Log4j
    JDK logging
    (2)日志级别
    在这里插入图片描述
    我们开发时,用的日志打印级别debug,发布项目用的级别是info或error。

    (3)在src下创建一个log4j.properties属性文件
    添加内容:

    # \u5168\u5C40\u65E5\u5FD7\u914D\u7F6E
    log4j.rootLogger=DEBUG, stdout
    # \u63A7\u5236\u53F0\u8F93\u51FA
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.err
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    

    8、Mybatis框架使用-xml方式2

    (1)创建项目,导入jar包
    (2)创建核心配置文件mybatis.cfg.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>
    	<environments default="mysql">
    		<environment id="mysql">
    			<!-- 配置事务管理器,推荐JDBC事务管理器 ,还有一种使用容器的事务管理-->
    			<transactionManager type="JDBC"></transactionManager>
    			<!-- 数据源获取方式,推荐POOLED,还有UNPOOLED和JNDI -->
    			<dataSource type="POOLED">
    				<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    				<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
    				<property name="username" value="root"/>
    				<property name="password" value="root"/>
    			</dataSource>
    		</environment>
    		<!-- <environment id="oracle">
    		</environment> -->
    	</environments>
    	
    	
    </configuration>  
    

    (2)创建核心配置文件mybatis.cfg.xml
    (3)创建实体类

    package com.mybatisTest.domain;
    
    public class Users {
    	private  int  id;
    	private  String userName;
    	private  String pwd;
    	private  String  name;
    	private  String  tel;
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    	public String getPwd() {
    		return pwd;
    	}
    	public void setPwd(String pwd) {
    		this.pwd = pwd;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getTel() {
    		return tel;
    	}
    	public void setTel(String tel) {
    		this.tel = tel;
    	}
    	public Users() {
    		
    	}
    	public Users(int id, String userName, String pwd, String name, String tel) {
    		super();
    		this.id = id;
    		this.userName = userName;
    		this.pwd = pwd;
    		this.name = name;
    		this.tel = tel;
    	}
    	@Override
    	public String toString() {
    		return "Users [id=" + id + ", userName=" + userName + ", pwd=" + pwd + ", name=" + name + ", tel=" + tel + "]";
    	}
    	
    }
    
    

    (4)创建Mapper接口UsersMapper

    package com.mybatisTest.mapper;
    
    import com.mybatisTest.domain.Users;
    
    public interface UsersMapper {
    	
    	int  addUsers(Users  user);
    	
    }
    

    (5)创建映射文件UsersMapper.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 --> 
    <mapper  namespace="com.mybatisTest.mapper.UsersMapper">
    	
    	<!-- id必须和接口的方法名一致 -->
    	<!-- 实体类的属性和表的列名称一致,不包括大小写 -->
    	<insert id="addUsers" parameterType="com.mybatisTest.domain.Users">
    		insert into users  values(null,#{userName},#{pwd},#{name},#{tel})
    	</insert>
    	
    </mapper>  
    

    (6)修改核心配置文件,添加映射。

    <?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>
    	<environments default="mysql">
    		<environment id="mysql">
    			<!-- 配置事务管理器,推荐JDBC事务管理器 ,还有一种使用容器的事务管理-->
    			<transactionManager type="JDBC"></transactionManager>
    			<!-- 数据源获取方式,推荐POOLED,还有UNPOOLED和JNDI -->
    			<dataSource type="POOLED">
    				<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    				<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
    				<property name="username" value="root"/>
    				<property name="password" value="root"/>
    			</dataSource>
    		</environment>
    		<!-- <environment id="oracle">
    		</environment> -->
    	</environments>
    	
    	<mappers>
    		<mapper  resource="com/mybatisTest/mapper/UsersMapper.xml"/>
    	</mappers>
    </configuration>  
    

    (7)测试类

    package com.mybatisTest.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    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 com.mybatisTest.domain.Users;
    import com.mybatisTest.mapper.UsersMapper;
    
    public class Test {
    
    	public static void main(String[] args) throws Exception {
    		String  xml="mybatis.cfg.xml";
    		InputStream  in=Resources.getResourceAsStream(xml);
    		SqlSessionFactory factory = new  SqlSessionFactoryBuilder().build(in);
    		SqlSession session = factory.openSession();
    		
    //		返回一个接口的代理实现类对象
    		UsersMapper mapper = session.getMapper(UsersMapper.class);
    		Users  user=new  Users(0, "十号", "555", "世豪", "15010002000");
    		int  i=mapper.addUsers(user);
    		System.out.println(i);
    		
    		session.commit();
    		session.close();
    	}
    
    }
    
    

    (8)工具类封装

    package com.mybatisTest.util;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    public class SessionFactory {
    	private static   SqlSessionFactory   ssf;
    	static{
    		String  xml="mybatis.cfg.xml";
    		InputStream in=null;
    		try {
    			in = Resources.getResourceAsStream(xml);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		ssf = new  SqlSessionFactoryBuilder().build(in);
    	}
    	
    	public  static  SqlSession  getSqlSession() {
    		return  ssf.openSession();
    	}
    	
    }
    

    9、mybatis.cfg.xml核心配置文件详细说明

    (1)properties
    加载属性文件

    <properties resource="db.properties"></properties>
    

    (2)settings
    设置mybatis的全局属性

    <settings>
    		<setting name="logImpl" value="LOG4J"/>
    </settings>
    

    (3)typeAliases
    为了在映射文件中写起来简单,我们可以给引用的类起别名。

    <typeAliases>
    		<!-- <package name="com.mybatisTest.domain"/> -->
    		<typeAlias type="com.mybatisTest.domain.Users"  alias="u"/>
    		<typeAlias type="java.lang.String"  alias="string"/>
    	</typeAliases>
    

    (4)plugins
    mybatis引入的插件设置(后续用到再说)

    <plugins>
    		<plugin interceptor=""></plugin>
    	</plugins>
    

    (5)Environments
    配置数据源,可以配置多个数据源,使用default指定采用哪个数据源

    <environments default="mysql">
    		<environment id="mysql">
    			<!-- 配置事务管理器,推荐JDBC事务管理器 ,还有一种使用容器的事务管理-->
    			<!-- mybatis事务管理器支持:JDBC和MANAGED -->
    			<!-- MANAGED将mybatis的事务管理给容器来管理 -->
    			<!-- mybatis官方推荐JDBC -->
    			<transactionManager type="JDBC"></transactionManager>
    			<!-- 数据源获取方式,推荐POOLED,还有UNPOOLED和JNDI -->
    			<!-- POOLED  采用连接池获取连接 -->
    			<!-- UNPOOLED  不采用连接池,每次都需创建连接 -->
    			<!-- JNDI 需要使用tomat配置的数据源 -->
    			<dataSource type="POOLED">
    				<property name="driver" value="${driver}"/>
    				<property name="url" value="${url}"/>
    				<property name="username" value="${username}"/>
    				<property name="password" value="${password}"/>
    			</dataSource>
    			<!-- <dataSource type="JNDI"  >
    				配置连接数据库的基本信息
                    <property name="data_source" value="java:comp/env/jdbc/mybats_jndi"></property>
    			</dataSource> -->
    		</environment>
    		<!-- <environment id="oracle">
    		</environment> -->
    	</environments>
    

    (6)mappers

    加载映射文件
    <mapper  resource="com/mybatisTest/mapper/UsersMapper.xml"/>
    <mapper class="com.mybatisTest.mapper.UsersMapper"/>
    <!-- 推荐方式,引入指定包下的所有映射文件,需要提供mapper接口 -->
    <package name="com.mybatisTest.mapper"/>
    <!--引入外部映射文件,了解-->
    <mapper url=""/>
    

    10、映射文件配置详解

    (1)映射文件名称
    可以任意指定。
    建议使用mapper接口名命名。
    如果没有接口,采用实体类名+Mapper.xml。
    (2)namespace
    指定我们配置的sql放在哪个空间下存储。
    一般建议使用mapper接口的全名。
    如果没有接口,可以任意指定,建议使用文件所在的包名+文件名。
    (3)sql的id
    和接口的方法名相同。
    没有接口,任意指定。
    (4)sql的参数类型
    参数类型主要有:简单类型,实体类型,Map类型
    推荐使用parameterType指定,不推荐parameterMap

    简单类型:parameterType=”java.lang.String”
    实体类型:parameterType=”com.mybatisTest.domain.Users”
    Map类型:parameterType=”java.util.Map”

    (5)返回值类型
    返回值类型主要有:简单类型、实体类型、List集合

    可以使用两种方式指定:resultType和resultMap

    集合只要指定元素的类型
    resultType=”com.mybatisTest.domain.Users”

    resultMap:
    第一种,结果集的列名和实体类的属性名不相同。
    第二种,多表查询。

    <resultMap type="com.mybatisTest.domain.Users" id="usersMap">
    		<id  column="id"  property="id"></id>
    		<result column="username"  property="userName2"/>
    		<result column="pwd"  property="pwd"/>
    		<result column="name"  property="name"/>
    		<result  column="tel"  property="tel"/>
    	</resultMap>
    	
    	<select id="findAll"  resultMap="usersMap">
    		select *  from  users
    	</select>
    

    (6)Sql中使用${}和#{}区别
    #底层用的sql对象PreparedStatement。
    Sql使用预处理方式生成,#{}相当于?,可以防止sql注入风险。
    简单类型:使用#{任意符号}获取

    $ 底层用的sql对象Statement。
    Sql使用字符串拼接,有sql注入风险。
    简单类型:使用${value}获取

    我们推荐使用#{},不推荐${}.

    package com.mybatisTest.domain;
    
    public class Fruit {
    	private  int  id;
    	private  String name;
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public Fruit() {
    		// TODO Auto-generated constructor stub
    	}
    	public Fruit(int id, String name) {
    		super();
    		this.id = id;
    		this.name = name;
    	}
    	@Override
    	public String toString() {
    		return "Fruit [id=" + id + ", name=" + name + "]";
    	}
    }
    
    package com.mybatisTest.mapper;
    
    import java.util.List;
    import java.util.Map;
    
    import com.mybatisTest.domain.Fruit;
    
    public interface FruitMapper {
    	int  addFruit(Fruit  ft);
    	int  addFruit2(Map  m);
    	Fruit  findFruitById(int  id);
    	List<Fruit>  findAllFruit();
    }
    
    <?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.mybatisTest.mapper.FruitMapper">
    
    	<insert id="addFruit2"  parameterType="map">
     		insert into  fruit  values(null,'${fname}')
     		<!-- insert into  fruit  values(null,#{fname}) -->
     	</insert>
     	
     	<insert id="addFruit"  parameterType="com.mybatisTest.domain.Fruit">
     		insert into  fruit  values(null,'${name}')
     		insert into  fruit  values(null,#{name})
     	</insert>
     	
     	<select id="findFruitById" parameterType="int" resultType="com.mybatisTest.domain.Fruit">
     		<!-- select *  from  fruit  where  id=${value} -->
     		select *  from  fruit  where  id=#{aa} 
     	</select>
     	
    </mapper>  
    package com.mybatisTest.test;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.ibatis.session.SqlSession;
    
    import com.mybatisTest.mapper.FruitMapper;
    import com.mybatisTest.util.SessionFactory;
    
    public class TestFruit {
    
    	public static void main(String[] args) {
    		SqlSession   session=SessionFactory.getSqlSession();
    		
    		FruitMapper  fm=session.getMapper(FruitMapper.class);
    		//添加水果
    //		Fruit  ft=new  Fruit(0,"apple");
    //		fm.addFruit(ft);
    		
    		Map  m=new  HashMap();
    		m.put("fname", "人参果");
    		fm.addFruit2(m);
    		
    		//通过id,查询水果
    //		Fruit f = fm.findFruitById(3);
    //		System.out.println(f);
    		
    		session.commit();
    		session.close();
    	}
    
    }
    
    

    11、模糊查询

    (1)第一种方式:拼好再传参
    Mapper接口:

    //模糊查询1
    	List<Fruit>   findFruitLikeName(String  name);
    

    Mapper映射:

    <!--模糊查询1  -->
     	<select id="findFruitLikeName"  resultType="com.mybatisTest.domain.Fruit">
     		select *   from  fruit  where  name  like #{value}
     	</select>
    
    //		模糊查询1
    		List<Fruit> likeList = fm.findFruitLikeName("%a%");
    		for (Fruit fruit : likeList) {
    			System.out.println(fruit);
    		}
    

    第二种,传参后再拼sql(推荐)

    //模糊查询2		
    	List<Fruit>   findFruitLikeName2(String  name);
    <!--模糊查询2  -->
     	<select id="findFruitLikeName2"  resultType="com.mybatisTest.domain.Fruit">
     		select *   from  fruit  where  name  like "%"#{value}"%"
     		<!-- select *   from  fruit  where  name  like '%${value}%' -->
     	</select>
    
    //		模糊查询2
    		List<Fruit> likeList = fm.findFruitLikeName2("a");
    		for (Fruit fruit : likeList) {
    			System.out.println(fruit);
    		}
    

    第三种,使用$

    <!-- select *   from  fruit  where  name  like '%${value}%' -->
    

    12、分页查询

    (1)分页查询分两大类
    一类,通过sql在数据库中分页,直接返回一页数据。
    另一类,查询所有数据,然后在内存中取出指定的一页数据。

    (2)sql分页
    Mysql数据库:limit 起始位置,每页的数量
    Oracle数据库:rownum,需要知道起始位置和结束位置

    以mysql为例:
    前端页面传给应用服务器的信息是pageNum,pageSize;
    计算:起始位置start=(pageNum-1)*pageSize,每页的数量pageSize
    最后将start和pageSize传给sql。

    //sql分页
    	List<Fruit>   findFruitPage(Map page);
    <!--sql分页  -->
     	<select id="findFruitPage" parameterType="map" resultType="com.mybatisTest.domain.Fruit">
     		select *  from  fruit  limit   #{start},#{pageSize}
     	</select>
    //		sql分页
    		int  pageNum=2;
    		int  pageSize=3;
    		
    		//计算
    		int  start=(pageNum-1)*pageSize;
    		
    		//传给sql
    		Map  m=new  HashMap();
    		m.put("start",start);
    		m.put("pageSize",pageSize);
    		
    		List<Fruit> pages = fm.findFruitPage(m);
    		for (Fruit fruit : pages) {
    			System.out.println(fruit);
    		}
    

    (3)内存分页

    //内存分页RowBounds
    	List<Fruit>  findAllFruitPage(String  name,RowBounds rb);
    <!-- 内存分页 -->
     	<select id="findAllFruitPage" parameterType="string" resultType="com.mybatisTest.domain.Fruit">
     		select *  from  fruit where  name=#{value}
     	</select>
    //		内存分页RowBounds,查询水果
    		List<Fruit> pages = fm.findAllFruitPage("apple",new  RowBounds(3, 4));
    		for (Fruit fruit : pages) {
    			System.out.println(fruit);
    		}
    

    (4)分页插件(PageHelper)
    内存分页
    (5)分页拦截器(Interceptor)
    Sql分页

    13、动态sql

    我们前面的项目需要实现多条件查询,你输入哪个字段就用哪个字段查询。
    需要使用标签:
    if where set forEach trim

    案例:

    package com.mybatisTest.domain;
    
    public class Product {
    	private  int  id;
    	private  String  name;
    	private  String  brand;
    	private  String  merchant;
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getBrand() {
    		return brand;
    	}
    	public void setBrand(String brand) {
    		this.brand = brand;
    	}
    	public String getMerchant() {
    		return merchant;
    	}
    	public void setMerchant(String merchant) {
    		this.merchant = merchant;
    	}
    }
    
    package com.mybatisTest.mapper;
    
    import java.util.List;
    import java.util.Map;
    
    import com.mybatisTest.domain.Product;
    
    public interface ProductMapper {
    	
    //	多条件查询方法
    	List<Product>  findByMore(Product  p);
    	
    	List<Product>  findByMore2(Map  m);
    }
    
    <?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.mybatisTest.mapper.ProductMapper">
    	
    	<select id="findByMore" parameterType="com.mybatisTest.domain.Product" resultType="com.mybatisTest.domain.Product">
    		select *  from  product
    		<!-- where 1=1
    		<if  test="name!=null">
    			and  name=#{name}
    		</if>
    		<if test="brand!=null">
    			and  brand=#{brand}
    		</if>
    		<if test="merchant!=null">
    			and  merchant=#{merchant}
    		</if> -->
    		<where>
    			<if  test="name!=null">
    				and  name=#{name}
    			</if>
    			<if test="brand!=null">
    				and  brand=#{brand}
    			</if>
    			<if test="merchant!=null">
    				and  merchant=#{merchant}
    			</if>
    		</where>
    	</select>
    	
    	
    	<select id="findByMore2"  parameterType="map"  resultType="com.mybatisTest.domain.Product">
    		select *  from  product  where  id  in
    		<foreach collection="list"  item="pp"  open="(" separator=","  close=")">
    			#{pp}
    		</foreach>
    	</select>
    </mapper>  
      
      
    package com.mybatisTest.test;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.ibatis.session.SqlSession;
    
    import com.mybatisTest.domain.Product;
    import com.mybatisTest.mapper.ProductMapper;
    import com.mybatisTest.util.SessionFactory;
    
    public class TestProduct {
    	public static void main(String[] args) {
    		
    		SqlSession sqlSession = SessionFactory.getSqlSession();
    		ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
    		
    		
    //		//设置查询条件
    //		Product  p=new  Product();
    //		p.setName("iphone12");
    //		p.setBrand("apple");
    //		//查询操作
    //		List<Product> findByMore = mapper.findByMore(p);
    //		for (Product product : findByMore) {
    //			System.out.println(product);
    //		}
    		
    		Map   m=new  HashMap();
    		List  list=new  ArrayList();
    		list.add(1);
    		list.add(2);
    		m.put("list", list);
    		List<Product> more2 = mapper.findByMore2(m);
    		for (Product product : more2) {
    			System.out.println(product);
    		}
    		
    		sqlSession.close();
    	}
    }
    
    

    14、mybatis框架使用-注解方式(基本使用)

    (1)加载mybatis相关jar
    (2)创建核心配置文件mybatis.cfg.xml
    (3)创建实体类

    package mybatisTest4.domain;
    
    import java.util.Date;
    
    public class Goods {
    	private  int  id;
    	private  String  name;
    	private  String  brand;
    	private  double  price;
    	private  int     count;
    	private  Date    birthdate;
    	private  String  info;
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getBrand() {
    		return brand;
    	}
    	public void setBrand(String brand) {
    		this.brand = brand;
    	}
    	public double getPrice() {
    		return price;
    	}
    	public void setPrice(double price) {
    		this.price = price;
    	}
    	public int getCount() {
    		return count;
    	}
    	public void setCount(int count) {
    		this.count = count;
    	}
    	public Date getBirthdate() {
    		return birthdate;
    	}
    	public void setBirthdate(Date birthdate) {
    		this.birthdate = birthdate;
    	}
    	public String getInfo() {
    		return info;
    	}
    	public void setInfo(String info) {
    		this.info = info;
    	}
    	public Goods() {
    		
    	}
    	public Goods(String name, String brand, double price, int count, Date birthdate, String info) {
    		super();
    		this.name = name;
    		this.brand = brand;
    		this.price = price;
    		this.count = count;
    		this.birthdate = birthdate;
    		this.info = info;
    	}
    	public Goods(int id, String name, String brand, double price, int count, Date birthdate, String info) {
    		super();
    		this.id = id;
    		this.name = name;
    		this.brand = brand;
    		this.price = price;
    		this.count = count;
    		this.birthdate = birthdate;
    		this.info = info;
    	}
    	
    }
    
    

    (4)创建mapper接口(使用注解定义sql)

    package mybatisTest4.mapper;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Select;
    import org.apache.ibatis.annotations.Update;
    
    import mybatisTest4.domain.Goods;
    
    /**
     * 定义操作数据库的方法
     * @author Administrator
     */
    public interface GoodsMapper {
    //	添加商品
    	@Insert("insert  into  goods  values(null,#{name},#{brand},#{price},#{count},#{birthdate},#{info})")
    	int addGoods(Goods  goods);
    //	删除商品
    	@Delete("delete  from  goods  where  id=#{id}")
    	int deleteGoods(int  id);
    //	修改商品
    	@Update("update  goods  set  name=#{name}  where id=#{id}")
    	int updateGoods(Goods  goods);
    //	查询一个商品
    	@Select("select *  from  goods  where  id=#{id}")
    	Goods  findGoodsById(int  id);
    //	查询所有商品
    	@Select("select  *  from  goods")
    	List<Goods>  findAllGoods();
    }
    
    

    (5)业务测试类:

    package mybatisTest4.service.impl;
    
    
    import java.util.Date;
    
    import org.apache.ibatis.session.SqlSession;
    
    import mybatisTest4.domain.Goods;
    import mybatisTest4.mapper.GoodsMapper;
    import mybatisTest4.util.SessionFactory;
    
    public class GoodsServiceImpl {
    	
    	public  int addGoods(Goods  goods) {
    		SqlSession sqlSession = SessionFactory.getSqlSession();
    		GoodsMapper mapper = sqlSession.getMapper(GoodsMapper.class);
    		
    		int  i=mapper.addGoods(goods);
    		
    		sqlSession.commit();
    		sqlSession.close();
    		return  i;
    	}  
    	
    	
    	public static void main(String[] args) {
    		
    		GoodsServiceImpl  service=new  GoodsServiceImpl();
    		Goods  goods=new  Goods("rongyaoplay", "rongyao", 1000, 1000, new Date(), "曾经是华为,现在是荣耀");
    		service.addGoods(goods);
    	}
    }
    
    

    15、mybatis框架使用-注解方式(动态sql)

    (1)复杂sql
    我们可以使用sql拼接,更建议使用:
    InsertProvider
    DeleteProvider
    UpdateProvider
    SelectProvider

    需要先写一个sql类,用于sql的获取。
    然后在接口中是Provider注解指定sql 来源于那个类的那个方法。

    package mybatisTest4.sql;
    
    import org.apache.ibatis.jdbc.SQL;
    
    import com.sun.org.apache.bcel.internal.generic.IFNULL;
    
    import mybatisTest4.domain.Goods;
    
    public class GoodsSql {
    	
    	public String updateGoods3(Goods  goods) {
    		return  new  SQL() {{
    			UPDATE("goods");
    			if(goods.getName()!=null&&!goods.getName().trim().equals("")) {
    				SET("name=#{name}");
    			}
    			if(goods.getBrand()!=null&&!goods.getBrand().trim().equals("")) {
    				SET("brand=#{brand}");
    			}
    			WHERE("id=#{id}");
    		}}.toString();
    	}
    	
    	public String  findGoodsMoreLike(Goods  goods) {
    		return  new  SQL() {{
    			SELECT("*");
    			FROM("goods");
    			if(goods.getName()!=null&&!goods.getName().trim().equals("")) {
    				AND().WHERE("name like \"%\"#{name}\"%\"");
    			}
    			if(goods.getBrand()!=null&&!goods.getBrand().trim().equals("")) {
    				AND().WHERE("brand like \"%\"#{brand}\"%\"");
    			}
    		}}.toString();
    	}
    }
    
    package mybatisTest4.mapper;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    import org.apache.ibatis.annotations.Update;
    import org.apache.ibatis.annotations.UpdateProvider;
    
    import mybatisTest4.domain.Goods;
    import mybatisTest4.sql.GoodsSql;
    
    /**
     * 定义操作数据库的方法
     * @author Administrator
     */
    public interface GoodsMapper {
    //	修改商品
    	@UpdateProvider(type=GoodsSql.class,method="updateGoods3")
    	int updateGoods3(Goods  goods);
    }
    
    

    (2)resultMap
    解决结果映射中属性和列名不同的现象。

    @Results(id="goodsMap",value= {
    			@Result(column="id",property="id",id=true),
    			@Result(column="name",property="name"),
    			@Result(column="brand",property="brand"),
    			@Result(column="price",property="price"),
    			@Result(column="count",property="count"),
    			@Result(column="birthdate",property="birthdate"),
    			@Result(column="info",property="info")
    	})
    

    16、逆向工程

    (1)使用mybatis-generator-core插件
    (2)下载和导入jar包
    https://github.com/mybatis/generator/releases

    mybatis-generator-core-1.4.0-javadoc.jar
    mybatis-generator-core-1.4.0-sources.jar
    mybatis-generator-core-1.4.0.jar

    (3)Src配置一个文件generatorConfig.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    <generatorConfiguration>
       <classPathEntry location="D:\hd2011\mybatisTest4\WebContent\WEB-INF\lib\mysql-connector-java-8.0.22.jar" />
       <context id="msqlTables" targetRuntime="MyBatis3">
      <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
        <jdbcConnection connectionURL="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"
         driverClass="com.mysql.cj.jdbc.Driver" password="root" userId="root" >
    
        <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>
        <javaTypeResolver>
                <property name="forceBigDecimals" value="false" />
            </javaTypeResolver>
        <javaModelGenerator targetPackage="com.springdemo.model" targetProject="mybatis_generator\src">
                <property name="enableSubPackages" value="true"/>
                <!-- 从数据库返回的值被清理前后的空格  -->
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
         <sqlMapGenerator targetPackage="mapping" targetProject="mybatis_generator\src">
                <property name="enableSubPackages" value="true"/>
            </sqlMapGenerator>
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.springdemo.dao" targetProject="mybatis_generator\src">
                <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
    
              <!--数据库表-->
              <table tableName="goods" domainObjectName="Goods"
                   enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                   enableSelectByExample="false" selectByExampleQueryId="false" >
                <property name="useActualColumnNames" value="false"/>
            </table>
      </context>
    </generatorConfiguration>
    

    (4)使用教程:
    使用eclipse插件,自动生成代码。
    https://www.cnblogs.com/xqz0618/p/javaweb05.html


    总结

    待。。。。。。。。。。。。。。。

    展开全文
  • MyBatis框架学习总结

    2020-12-23 09:57:52
    MyBatis框架学习总结 1.Mybatis介绍 一个优秀的基于java的持久层框架,内部封装了jdbc,使开发者只需要关心sql语句本身,而不需要花费经历在如何加载驱动,创建链接,创建statement等繁杂的过程, mybatis通过注解和...

    MyBatis框架学习总结

    1.Mybatis介绍

    一个优秀的基于java的持久层框架,内部封装了jdbc,使开发者只需要关心sql语句本身,而不需要花费经历在如何加载驱动,创建链接,创建statement等繁杂的过程, mybatis通过注解和xml配置的方式将要执行各种statement配置起来。并通过java对象和statement中的动态参数进行映射生成最终执行的sql语句
    最后mybatis框架执行sql语句并将其封装为java对象返回采用ORM思想解决了实体与数据库映射的问题,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作。

    原始jdbc开发存在的问题如下:
    1.数据库创建及频繁释放造成系统资源浪费
    2.sql语句在代码中硬编码,实际运用中sql的变化较大,sql变动需要改变java代码
    3.查询操作,需要手动将结果集里的数据封装到实体中,插入操作时,需要手动将实体的数据设置到sql语句的占位符

    解决方案:

    1.使用数据库连接池技术
    2.使用xml配置的方式配置sql语句
    3.使用反射内省的技术自动将实体和表进行属性与字段的自动映射

    ORM(Object Relational Mapping)对象关系映射,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 ,即将程序中的对象自动的持久化到关系数据库中

    ORM简介:

    O(对象模型):
    实体对象,即我们在程序中根据数据库表结构建立的一个个实体Entity。

    R(关系型数据库的数据结构):

    即我们建立的数据库表。

    M(映射):

    从R(数据库)到O(对象模型)的映射,可通过XML文件映射。
    如图:当表实体发送变化时,ORM会帮助我们把实体的变化映射到数据库表。

    在这里插入图片描述

    作用

    ORM框架自动实现Entity实体的属性与关系型数据库字段的映射。CRUD的工作则可以交给ORM来自动生成代码方式实现。隐藏了数据访问细节,“封闭”的通用数据库交互,他使得我们的通用数据库交互变得简单易行,并且完全不用考虑SQL语句。大大提高我们开发效率, 这样一来也减少我们维护一个复杂 缺乏灵活性数据访问层的成本。

    2.一对一映射

    1.嵌套结果

    是关联的意思,常被用来表示(has-one)类型的关联。就是对象1里面关联另
    一个对象2

    <!-- 独立的Address封装映射 -->
    <resultMap type="Address" id="AddressResult">
    <id property="addrId" column="addr_id" />
    <result property="street" column="street" />
    <result property="city" column="city" />
    <result property="state" column="state" />
    <result property="zip" column="zip" />
    <result property="country" column="country" />
    </resultMap>
    <!-- Student封装映射,里面关联上Address的封装映射 -->
    <resultMap type="Student" id="StudentWithAddressResult">
    <id property="studId" column="stud_id" />
    <result property="name" column="name" />
    <result property="email" column="email" />
    <result property="dob" column="dob" />
    <result property="phone" column="phone" />
    <association property="address" resultMap="AddressResult" />
    </resultMap>
    <select id="selectStudentWithAddress" parameterType="int"
    resultMap="StudentWithAddressResult">
    select
    s.stud_id, s.name, s.email,s.dob,s.phone,
    a.addr_id, a.street, a.city, a.state, a.zip, a.country
    from
    students s
    left outer join addresses a on s.addr_id = a.addr_id
    where
    stud_id = #{id}
    </select>
    

    2.嵌套查询

    <!-- 独立的Address封装映射 -->
    <resultMap type="Address" id="AddressResult">
    <id property="addrId" column="addr_id" />
    <result property="street" column="street" />
    <result property="city" column="city" />
    <result property="state" column="state" />
    <result property="zip" column="zip" />
    <result property="country" column="country" />
    </resultMap>
    <!-- 独立的select查询,专门查询Address -->
    <select id="findAddressById" parameterType="int" resultMap="AddressResult">
    select * from addresses
    where addr_id=#{id}
    </select>
    <!-- Student封装映射,里面关联了查询address使用的select语句,并指定数据库表中的这个关联的外
    键列的名字,这里是addr_id -->
    <resultMap type="Student" id="StudentWithAddressResult">
    <id property="studId" column="id" />
        <result property="name" column="name" />
    <result property="email" column="email" />
    <result property="dob" column="dob" />
    <result property="phone" column="phone" />
    <association property="address" column="addr_id" select="findAddressById" />
    </resultMap>
    <!-- 查询Student的select语句,这里不用写多表查询,因为对于address的关联查询,已经在上边定义
    好了,并且在结果映射中关联进来了 -->
    <select id="selectStudentWithAddress" parameterType="int"
    resultMap="StudentWithAddressResult">
    select
    id,name,email,dob,phone,addr_id
    from
    students
    where
    id = #{id}
    </select>
    

    在此方式中, 元素的select属性被设置成了id为findAddressById的语句。
    两个分开的SQL语句将会在数据库中分别执行,第一个通过id查询student信息,而第二个调用
    findAddressById来加载address信息。
    addr_id列的值将会被作为输入参数传递给selectAddressById语句作为参数进行条件查询。

    总结对比:
    嵌套结果
    一条sql语句,查询出所有表中的数据,然后交给一个ResultMap去映射,这个ResultMap只负责映射
    封装一部分数据,另一部分数据交给第二个ResultMap来映射,这个俩个ResultMap之间,使用标签
    进行关联
    例如,
    嵌套查询
    把之前一条sql语句,拆分成多条sql语句,每条sql语句只查询一张表并封装一部分数据,然后使用
    标签 将多条sql语句关联起来,最后把结果合并起来就是完整的查询结果
    例如,

    3.一对多映射

    标签可以用来将多行课程结果映射成一个课程Course对象的集合。

    类似于一对多

    4.多对多映射

    参照一对多

    5.动态(动态SQL是Mybatis强大的特性之一)

    if

    被用来通过条件嵌入SQL片段,如果条件为true,则相应地SQL片段将会被添加到SQL语句中。
    假定有一个课程搜索界面,设置了讲师(Tutor)下拉列表框,课程名称(CourseName)文本输入框,
    开始时间(StartDate)输入框,结束时间(EndDate)输入框,作为搜索条件,其中课讲师下拉列表是必
    须选的,其他的都是可选的。

    choose

    有时候,查询功能是以查询 类别 为基础的。
    例如,页面中有一个下拉列表,可以选择查询的类别,可以选择根据讲师查询、或者根据课程名查询、
    或者根据时间查询等等,选择了列表之后,再输入关键字进行查询。

    搭配使用

    where

    有时候,所有的查询条件应该是可选的。
    在需要使用至少一种查询条件的情况下,可以直接使用WHERE子句,如果有多个条件,需要在条件中添
    加AND或OR。

    foreach

    另外一个强大的动态SQL语句构造标签是
    它可以迭代遍历一个数组或者集合,构造AND/OR条件或一个IN子句。
    假设查询tutor_id为 1,3,6的讲师所教授的课程,我们可以传递一个tutor_id组成的列表给映射语句,然
    后通过 遍历此列表构造动态SQL。

    trim

    元素和 元素类似,同时 提供了添加 前缀/后缀 或者 移除 前缀/后缀 的功能。

    <select id="searchCourses" parameterType="map" resultMap="CourseResult">
    SELECT * FROM COURSES
    <trim prefix="WHERE" suffixOverrides="and">
    <if test=" tutorId != null ">
    TUTOR_ID = #{tutorId} and
    </if>
    <if test="courseName != null">
    name like #{courseName} and
    </if>
    </trim>
    </select>
    

    prefix表示有一个if成立则插入where语句
    suffix表示后缀,和prefix相反
    suffixOverrides="and"表示如果最后生成的sql语句多一个and,则自动去掉.
    prefixOverrides的意思是处理前缀,和suffixOverrides相反

    set

    元素和 元素类似,但是set元素只是针对update更新语句使用的。

    <update id="updateStudent" parameterType="Student">
    update students
    <set>
    <if test="name != null">name=#{name},</if>
    <if test="email != null">email=#{email},</if>
    <if test="phone != null">phone=#{phone},</if>
    </set>
    where id=#{studId}
    </update>
    
    展开全文
  • MyBatis框架学习笔记01

    2021-03-03 19:34:11
    包,然后在包里创建测试类 - TestUserMapper 2、运行测试方法 - testFindAll() 总结: 今天下午我们学习框架的第一课,由于接触到了新的知识点,刚开始的时候感觉比较简单,但是到了后面一点进入正题的时候,就...

    一、创建数据库与表
    1、在Navicat里面创建MySQL数据库testdb
    在这里插入图片描述
    2、创建用户表-t_user
    在这里插入图片描述
    执行SQL语句来创建用户表

    在这里插入图片描述

    查看用户表结构
    在这里插入图片描述
    3、在用户表里插入3条记录
    INSERT INTO t_user VALUES (‘1’, ‘李洪刚’, ‘20’, ‘江阳区嘉裕花园3栋四楼15#’);
    INSERT INTO t_user VALUES (‘2’, ‘王云华’, ‘30’, ‘纳溪区大渡镇红鱼村三大队’);
    INSERT INTO t_user VALUES (‘3’, ‘郑小翠’, ‘21’, ‘江阳区老窖花园2栋五楼15号’);

    执行SQL语句插入记录

    在这里插入图片描述查看用户表记录

    在这里插入图片描述
    三、案例演示MyBatis基本使用

    (一)创建Maven项目 - MyBatisDemo
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    (三)创建与用户表对应的用户实体类 - User

    在这里插入图片描述

    用户实体类的属性对应用户表的字段(列)
    在这里插入图片描述
    在这里插入图片描述
    (四)创建用户实体关系映射配置文件
    在resources目录里创建mapper子目录,然后在里面创建实体关系映射配置文件 -UserMapper.xml
    在这里插入图片描述
    (五)创建MyBatis配置文件
    在resources目录里创建mybatis-config.xml

    在这里插入图片描述
    (六)创建日志属性文件
    在resources目录里创建log4j.properties文件
    在这里插入图片描述
    (七)创建测试类测试用户操作
    1、创建测试类 - TestUserOperation
    在test/java目录里创建net.gzm.mybatis.bean包,然后在包里创建测试类 - TestUserOperation

    在这里插入图片描述
    (二)创建测试类测试用户映射器接口
    1、创建测试类 - TestUserMapper
    在test/java里创建net.gzm.mybatis.mapper包,然后在包里创建测试类 - TestUserMapper

    在这里插入图片描述
    2、运行测试方法 - testFindAll()
    在这里插入图片描述
    总结:
    今天下午我们学习了框架的第一课,由于接触到了新的知识点,刚开始的时候感觉比较简单,但是到了后面一点进入正题的时候,就遇到了困难,比如说配置,最搞笑的是,我居然把自己的MYSQL的密码忘了,就只能先跟着老师走,到后面再来解决密码的问题,导致我在同学们已经接近尾声了我还在手忙脚乱的弄自己的密码,直到下课我也没有想起来密码是多少,到了晚自习的时候终于想起来了,然后才完成今天老师讲的所有的内容,今天也给了我自己一个教训就是记性不好就要随时做好笔记,不然到了要用的时候记不起来真的会很麻烦。

    展开全文
  • 文章目录一、简介1.1、什么是Mybatis1.2、持久化1.3、为什么需要Mybatis二、第一个Mybatis程序2.1、搭建环境2.2、创建一个子模块2.3、编写代码2.4、测试2.5、小结三、CRUD3.1、Mybatis传递多个参数(万能的Map)四、...

    Mybatis

    所需环境回顾
    JDK1.8JDBC
    Mysql5.7/8.0Mysql
    maven3.6.1Maven
    IDEAJunit

    SSM(Spring + SpringMvc + Mybatis)框架:配置文件相关的。学习的最好方式:官方文档

    一、简介

    1.1、什么是Mybatis

    在这里插入图片描述

    • MyBatis 是一款优秀的持久层框架
    • 它支持自定义 SQL、存储过程以及高级映射。
    • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
    • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
    • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github

    获得Mybatis

    • maven仓库
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    

    1.2、持久化

    数据持久化

    • 持久化就是将程序的数据在持久状态(硬盘/外存中)和瞬时状态(内存中)转化的过程

    • 内存(Random Access Memory,RAM):断电即失

      在大学里面看过一本关于早期工业革命历史的书,学习到有个叫继电器的器件,早期内存核心就是继电器,具体构造是个弹片,随着电位信息拨动(挨上就是1,没挨上就是0,这也就是为什么计算器底层是二进制的又一证据),这个继电器的电位信息来自于地址总线(几根就是我们说的32/64操作系统,说的就是内存大小),因为直接由地址总线控制,所以能直接定位(Access)某个位置,这也就是为什么内存速度快。同时内存核心元件是继电器,一旦断电,继电器拨片会立马回弹,导致回到初始状态,即数据都变成000000序列了,数据就不复存在了。这就是RAM存储器的特性,速度快,怕断电。在计算机中充当着内存的角色。毕竟是课外学习到的知识,也不是科班,所以可能有误,望高人指出。

    • 数据库(JDBC), io文件持久化。

      本质上都是放在外存上。学习的课外知识。分为固态硬盘和机械硬盘。机械硬盘,你可以看作小时候看的碟机的CD运行原理,有一个小小的指针放在上面随着转动这就是再读取了。所以机械硬盘怕摔,针头偏移了的话,没咬合住就读取不了了。固态硬盘,半导体技术,懵逼,不懂,只知道他有个专业术语是颗粒。

    为什么要持久化

    • 假如做一个学生信息管理系统,我们从view层获得一个学生信息,一个老师早上忙活大半天录了300个学生,中午吃饭去电脑断电,在内存(RAM)中的数据,断电丢失,全部没有了,白忙活一场。所以我们要把它转到外存去,长期保存,转移到数据库里,看表容易多了。
    • 内存太贵了

    持久层:Dao层,Service层,Controller层。

    • 完成持久化工作的代码块
    • 层界线十分明显

    1.3、为什么需要Mybatis

    • 方便帮助程序员将数据存入到数据库中
    • 传统的JDBC代码太复杂了,简化,框架,自动化。
    • 不用Mybatis也可以,学了更容易上手。技术没有高低之分
    • 优点
      • 简单易学
      • 灵活
      • sql和代码的分离,提高了可维护性。
      • 提供映射标签,支持对象与数据库的orm字段关系映射
      • 提供对象关系映射标签,支持对象关系组建维护
      • 提供xml标签,支持编写动态sql。

    总结及自己的思考

      Mybatis框架完全可以不学,你可以用更加全自动的Hibernate框架。Hibernate全自动框架,Mybatis半自动框架。理解就在于hibernate将sql语句都内部处理了(黑箱操作),用户使用时只需调用相关api即可。而mybatis还需自己写sql语句,这样更加灵活。因为不同的需求可能需要不同程度的sql语句,sql这种变化大的由外面来写最好。

      还是那句话,框架没有好坏之分,但现在主流的方向就是这个,所以为了迎合,必须要学。

      同时,对于框架,我只想说,不用太放在心上,刨根问题,就是人家为我们做好的工具,你可以拿来使用,只不过要学习人家规定的语法/配置文件。你完全可以给一个不懂底层实现的人让他去学框架的使用,使用框架使得开发越来越快。框架就是人家定好的规则,你去学习使用完成自己的目标,做一个API的调用者,很简单;但要做一个框架的开发者(工具的建造者),很难。所以学习框架就是个上山和下山的过程,上山学习如何快速使用,下山,刨根问题,去探究人家这个功能是怎么实现的。深度和广度的问题,取决在于你。

    二、第一个Mybatis程序

    思路:搭建环境–>导入Mybatis–>编写代码–>测试

    2.1、搭建环境

    搭建数据库

    CREATE DATABASE `mybatis`;
    
    USE mybatis;
    
    CREATE TABLE `user`(
      `id` INT(20) NOT NULL,
      `name` VARCHAR(30) DEFAULT NULL,
      `pwd` VARCHAR(30) DEFAULT NULL,
      PRIMARY KEY(`id`)
    )ENGINE=INNODB DEFAULT CHARSET=utf8;
    
    INSERT INTO `user` (`id`,`name`,`pwd`) VALUES
    (1,'狂神','123456'),
    (2,'张三','456852'),
    (3,'李四','qwertyuiop');
    

    新建项目

    1. 新建一个普通的maven项目

    2. 删除src目录(使用父工程子项目模式来做,为了一呼百应)

    3. 父工程pom.xml导入maven依赖

        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.26</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.2</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    

    2.2、创建一个子模块

    创建一个子模块,该子模块也是maven的普通项目。

    • 编写mybatis的核心配置文件

    在子模块的resource目录(web学习中明白打包导出后直接就在当前目录下)下编写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">
    <configuration>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT%2B8&amp;useSSL=false"/>
                    <property name="username" value="root"/>
                    <property name="password" value="456852"/>
                </dataSource>
            </environment>
        </environments>
    
    </configuration>
    

    该配置文件不要写中文注释(硬要写UTF-8改为UTF8/GBK)!

    &amp;代替&

    • 编写mybatis工具类
    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;
    
    //本质上在 sqlSessionFactory 建造 sqlSession
    public class MybatisUtil {
        private static SqlSessionFactory sqlSessionFactory;
    
        static {
            try {
                //使用MybatisUtils第一步:获取sqlSessionFactory对象
                String resource = "mybatis-config.xml";
                InputStream resourceAsStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
        // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
        public static SqlSession getSqlSession() {
            return sqlSessionFactory.openSession();
        }
    }
    

    2.3、编写代码

    • 实体类pojo

    写在对应包下,与数据库表一一对应。

    public class UserModel {
        private int id;
        private String name;
        private String pwd;
     
        //get,set,toString来一套
    }
    
    • DAO接口
    public interface IUserDao {
        List<UserModel> getUserList();
    }
    
    • 接口实现类由原来的UserDaoImpl转变为一个Mapper配置文件
    <?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.kuang.dao.IUserDao">
    
        <select id="getUserList" resultType="com.kuang.pojo.UserModel">
        SELECT * FROM mybatis.`user`
      </select>
    </mapper>
    

    右边感叹警告,未配置数据库。配置Mysql,方便快速查询相应表和字段。

    • 去mybatis的核心配置文件进行配置
    	<mappers>
            <mapper resource="com/kuang/dao/userDaoMapper.xml"/>
        </mappers>
    

    因为此时要访问的是一个目录下的xml文件,而不是类文件,所以要用/,而不用.

    2.4、测试

    junit测试,应该去test目录下进行。所以要在test目录下建立和src一样的包结构

    import com.kuang.pojo.UserModel;
    import com.kuang.util.MybatisUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.List;
    
    public class userDaoTest {
        @Test
        public void userDaoTest() {
            //第一步:获得SqlSession对象
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            //执行
            IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    
            List<UserModel> userList = userDao.getUserList();
            for (UserModel userModel : userList) {
                System.out.println(userModel);
            }
            sqlSession.close();
        }
    }
    

    可能遇到的问题

    1. 配置文件没有注册

    要去mybatis的核心配置文件下进行相关xml文件的注册绑定

    1. 绑定接口错误(namespace)
    2. 方法名不对(id)
    3. 返回类型不对(resultType)

    在这里插入图片描述

    1. Maven导出资源问题

    Mybatis为了增加关联性,我们经常把xml文件等配置文件和类放在一起。但是默认导入包不会导出src下的配置文件。所以在父工程下的pom.xml下加过滤器。

    为了关联性:

    在这里插入图片描述

    为了不被过滤,所以需要在pom.xml添加

        <build>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
        </build>
    

    2.5、小结

      Mybatis就是把我们以前写userDaoImple实现类做法转成了写一个xml文件的做法。让我们以前写的好多代码(connection、preparestatment等)得到简化。

    演化过程

    以前做法Mybatis做法
    implements 接口namespace = “包权限接口名”
    实现接口方法id=“接口方法名”
    返回值resultType = “带包权限类名”

      Mybatis就是把实现类变为写一个xml标签,其标签体专注SQL语句。写完该xml,记得要去mybatis的核心配置文件进行注册namespace是绑定,去核心配置文件添加叫注册

    三、CRUD

    • id:就是对应的namespace中的方法名;
    • resultType:SQL语句的返回值!
    • parameterType:参数类型。

    有了Mybatis以后的CRUD步骤都是一致的。

    编写接口—>编写接口对应的mappeer.xml中的sql语句—>测试(固定四步,打开sqlSession;获取sqlSession.getMapper(接口.class);进行相关操作;最后关闭sqlSession)

    Select

    选择,查询语句;

    1. 编写接口
        //名字命名起的越底层,高层越方便调用以达到复用,DAO和Service想成两个人之间的对话
        UserModel getUserRecordById(int id);
    
    1. 编写对应的mappeer中的sql语句
        <select id="getUserRecordById" parameterType="int" resultType="com.kuang.pojo.UserModel">
            SELECT * FROM mybatis.`user` where id = #{id}
        </select>
    
    1. 测试
        @Test
        public void selectTest() {
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            IUserDao userDao = sqlSession.getMapper(IUserDao.class);
            System.out.println(userDao.getUserRecordById(2));
            sqlSession.close();
        }
    

    Insert

        <!--对象中的属性可以直接取出来-->
        <insert id="addUserRecord" parameterType="com.kuang.pojo.UserModel">
            insert into mybatis.user (id, name, pwd) VALUES (#{id},#{name},#{pwd})
        </insert>
    

    Update

        <update id="updateUserRecord" parameterType="com.kuang.pojo.UserModel">
            update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id}
        </update>
    

    Delete

        <delete id="deleteUserRecordById" parameterType="int">
            delete from mybatis.user where id = #{id}
        </delete>
    

    需要注意的是:增删改操作必须进行业务提交sqlSession.commit();

    期间发现几个问题。

    1. 参数名称为一个时可以任意命名,id换成goushi,任意都行,两边驴唇不对马嘴都可以,这应该和mybatis底层有关,到时候深入研究。(后面万能的map学到了,单个参数都可以不用写,自动匹配到形参)
    2. 增删改这几个操作,返回值可以为int(但此int不是受影响行行数),可以为boolean,我不理解它返回值为什么可以有两个,应该和底层有关,学习到再说。

    有可能错误的原因

    • 标签要匹配。update标签是UPDATE的SQL语句使用的,delete标签是DELETE的SQL语句使用的。
    • resoure绑定mapper路径要用/链接。前面说过了要访问的是一个目录下的xml文件,而不是类文件,所以要用/,而不用.

    3.1、Mybatis传递多个参数(万能的Map)

    回顾上面写的,修改(update)用户时,不应该传一个user,而应该传递id(改哪个),name、pwd(改成什么);或者考虑这么一个问题,如果一个实体类有100个字段值,你填都要填半天,我们只填自己需要的。

    IUserDao

        //重名了,测试看可以吗?  不可以,报错,Mapped Statements collection already contains
        //map映射已经有一个了,也就是说方法的重载在mybatis是不可行的
        //boolean updateUserRecord(Map<String,Object> map);
        boolean updateUserRecordNew(Map<String,Object> map);
    

    userDaoMapper.xml

        <update id="updateUserRecordNew">
            #这里的 updateName updatePwd whichId 必须和塞的时候放的键值一模一样
            update mybatis.user set name = #{updateName},pwd = #{updatePwd} where id = #{whichId}
        </update>
    

    测试

    	@Test
        public void newUpdate() {
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            IUserDao userDao = sqlSession.getMapper(IUserDao.class);
            Map<String, Object> map = new HashMap<>();
            map.put("whichId",0);
            map.put("updateName","王小明");
            map.put("updatePwd","mzby");
            //#这里的 塞的键值updateName updatePwd whichId 必须和xml取得时候保持一致
            //否则执行时返回的为0/false,且数据库没发生变化
            System.out.println("成功了吗?" + userDao.updateUserRecordNew(map));
            sqlSession.commit();
            sqlSession.close();
        }
    

    因此,建议Mybatis在传递多个参数时,使用map(设置 parameterType=“map”),直接在sql中取出key即可!

    可以但不建议传输对象实例,做法(设置parameterType=“带包权限类名”),直接在sql中取出对象的属性即可!

    只有一个基本类型参数的情况下,可以自己在sql中取到,且不管形参名字!底层原因好像就是以下标取得的。

    多个参数用Map,或者注解!

    其他多参传递参考这个博文 即可,但最简单最直观还是建议使用Map(官方也是这么说的)。

    经过这次例子,还学到了Mybatis中方法不可以重载,因为你是通过名字绑定的,重名问题解决不了。从这回想起方法重名(重载)的底层原理,我们看到的方法名其实在底层根本不是这个,而是带数字的,形如fun_1(),fun_2()之类的,不过程序员这层看它们名字相同。

    模糊查找

    1. Java代码执行的时候,传递通配符% %
    List<User> userList = mapper.getUserLike("%李%");
    
    1. 在sql拼接中使用通配符!
    select * from mybatis.user where name like "%"#{value}"%"
    

    四、配置解析

    4.1、核心配置文件

    • mybatis-config.xml(官方建议这个命名,放在resources目录下,随着java代码一起导出在target里)
    • MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息
    configuration(配置)
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
    environment(环境变量)
    transactionManager(事务管理器)
    dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)
    

    4.2、环境变量(environments)

    MyBatis 可以配置成适应多种环境。这种机制有助于将 SQL 映射应用于多种数据库(Mysql,Oracle)之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置。

    不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

    学会使用配置多套运行环境

    Mybatis默认的事务管理器就是JDBC,连接池:POOlED

    		<environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                <!--....--> 
                </dataSource>
            </environment>
    

    4.3、属性

    我们可以通过properties属性来实现引用配置文件

    这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。典型的 Java 属性【db.properties】

    db.properties 放在resources目录下,打包后直接在classpath下

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
    username=root
    password=456852
    

    在核心配置文件中引用

        <!--核心配置文件中引入,下面数据库连接${}就可以用-->
        <properties resource="db.properties">
            <!--还可以直接添加一些属性-->
            <property name="usernameOne" value="root"/>
            <property name="password" value="qwert"/>
        </properties>
    
    • 可以直接引入外部文件
    • 可以再其中增加一些属性配置(property)
    • 如果有外部配置和xml的property标签都有的同一字段,会优先使用外部配置文件的

    并且,从这个问题从中学到了,XML文件标签是有结构顺序的!!!

    可以看到,如果相关XML前后位置写错,IDEA也会报错的。

    你如果深入到底层去看XMLConfigBuilder这个类parseConfiguration方法,可以看到它解析就是有顺序的

    private void parseConfiguration(XNode root) {
        try {
          //issue #117 read properties first
          propertiesElement(root.evalNode("properties"));
          Properties settings = settingsAsProperties(root.evalNode("settings"));
          loadCustomVfs(settings);
          loadCustomLogImpl(settings);
          typeAliasesElement(root.evalNode("typeAliases"));
          pluginElement(root.evalNode("plugins"));
          objectFactoryElement(root.evalNode("objectFactory"));
          objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
          reflectorFactoryElement(root.evalNode("reflectorFactory"));
          settingsElement(settings);
          // read it after objectFactory and objectWrapperFactory issue #631
          environmentsElement(root.evalNode("environments"));
          databaseIdProviderElement(root.evalNode("databaseIdProvider"));
          typeHandlerElement(root.evalNode("typeHandlers"));
          mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
          throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
    

    在这里插入图片描述

    4.4、类型别名(typeAliases)

    • 类型别名可为 Java 类型设置一个缩写名字。
    • 意在降低冗余的全限定类名书写
    <typeAliases>
        <typeAlias type="com.kuang.pojo.User" alias="User"/>
    </typeAliases>
    

    在实际开发中,工作项目下,还是会使用完全限定名,使得以后一眼就能看明白!

    4.5、设置

    还是都参考官方文档

    这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

    最为重要的四个参数,要眼熟。

    设置名描述有效值默认值
    cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true/falsetrue
    lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true/falsefalse
    logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J LOG4J LOG4J2 JDK_LOGGING COMMONS_LOGGING STDOUT_LOGGING NO_LOGGING
    mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true/falsefalse

    驼峰转换有时候需开启,我们知道数据库字段名一般都用下划线隔开,因为数据库对大小写不敏感,而且Oracle数据库都是全大写,所以要用下划线隔开,而实体类中的属性名是以驼峰命名法走的,因此两者挂钩需要进行修改。

    4.6、映射器(mappers)

    前面我们说过,当相关接口的实现的mapper.xml(形如userDaoMapper.xml)写出来后,就立刻去核心配置文件注册它。

    方式一:【极其推荐使用】万能,写对绝对可用

        <mappers>
            <mapper resource="com/kuang/dao/userDaoMapper.xml"/>
        </mappers>
    

    我们知道此时是根据路径去定位相关文件,因此这里用的是/而不是.。或者确切的来说,只有Java的目录结构用.来进行深入访问,而其他所有文件都和操作系统保持一致。

    方式二:【有额外要求,不推荐使用】使用class文件绑定注册

        <mappers>
            <mapper class="com.kuang.dao.UserMapper"></mapper>
        </mappers>
    
    
    • 接口和他的Mapper配置文件必须同名
    • 接口和他的Mapper配置文件必须在同一个包下

    4.7、其他

    都参考官方文档。

    五、生命周期和作用域

    这一节,我想拿出来单独说,因为里面包含的是设计思想。

    作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题

    5.1、SqlSessionFactoryBuilder

    • 一旦创建了SqlSessionFactoryBuilder ,就不再需要它了
    • 局部变量

    可以深入到源码去看,SqlSessionFactoryBuilder最主要都是为外提供了build方法,都是为了得到一个SqlSessionFactory。而这些build方法,其本质都是在解析核心配置XML文件!

    可以这样理解:其作用读取XML文件,根据XML(environment标签)实例出不同的SqlSessionFactory,SqlSessionFactoryBuilder就是读取核心配置文件产生SqlSessionFactory,而我们知道有个environment标签,会产生不同的环境,SqlSessionFactoryBuilder就是根据这个来创造SqlSessionFactory的。

    这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

    5.2、SqlSessionFactory

    • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。(其随着程序开始开始,程序关闭而结束)
    • 因此 SqlSessionFactory 的最佳作用域是应用作用域。
    • 最简单的就是使用单例模式或者静态单例模式。

    SqlSessionFactory是一个对应环境(environment标签)的实例,可以理解为数据库连接池,程序运行中一直存在。某个数据库(JDBC/Oracle)的数据库连接池。应该单例,一次程序完整运行,一次环境(某个数据库),随着一次程序的关闭再关闭。单例原因:一次程序运行只能使用一个环境(用一个数据库)。

    其源码主要方法都是一个openSession(),从这可以更加确定的认为其是一个数据库连接池,对外提供数据库连接,可提供多个。

    5.3、SqlSession

    • 类似Connection和Preparestatment的集合体
    • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
    • 用完之后需要赶紧关闭,否则资源被占用。

    SqlSession可以看作从数据库连接池(SqlSessionFactory)得到的一次连接(具有connection和preparestatment的能力)。线程不安全,用完及时归还。

    我们可以看它的源码,SqlSession就是一个接口,其里面含有

    void commit();
    void rollback();
    Connection getConnection();
    <T> T getMapper(Class<T> type);	//mybatis最主要用这个
    

    从上述看来,它就是Connection和Preparestatment的集合体。

    5.4、Mybatis三大对象映像图

    在这里插入图片描述

    六、解决属性名和字段名不一致问题

    Java采用驼峰命名原则,而数据采用下划线分割命名原则,这两肯定会有不一致的情况。

    例如,如下情况。

    数据库中的字段

    在这里插入图片描述

    实体类

    public class UserModel {
        private int id;
        private String name;
        private String password;
    }
    
    

    测试出现问题

    在这里插入图片描述

    仔细查询,明白问题所在,在相关mapper的xml文件中的SQL语句

    select * from mybatis.user where id = #{id}
    //同等于
    select id,name,pwd from mybatis.user where id = #{id}
    
    

    *是选中数据库的所有字段名,所以选的是pwd,而此时实体类属性名为password,两者不一致,所以导致没查出来(后面分析很明显这是使用了反射机制)。

    6.1、解决方法一:取别名(数据库层面)

     select id,name,pwd as password from mybatis.user where id = #{id}
    

    只需要构造sql语句时将它的别名和属性名一致即可。分析其原因:其实就是sql执行后会建立一张新表,这个表的名字就是按上面走的,然后这时候就一致了(就方便反射了)。

    这种解决方式太low了,取巧方式,如果有很多字段和属性不一致就要大量增加。Mybatis有自己的解决方式。

    6.2、解决方式二:结果映射resultMap(Java层面,重点)

    属性名:id name password
    字段名:id name pwd
    

    在相关mapper的XML里将这种映射关系描述出来,在一个mapper标签里里表述出来

    <mapper namespace="com.kuang.dao.IUserDao">
        <resultMap id="resultMapOne" type="com.kuang.pojo.UserModel">
            <result property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="password" column="pwd"/>
        </resultMap>
    
        <select id="getUserList" resultMap="resultMapOne">
    
            select * from mybatis.user
        </select>
    </mapper>
    

    其实相同的可以删除。可以将id和name的映射删除也不影响结果。

    6.3、用例子明白resultMap底层是反射执行

      说实话看到这个resultMap,我有很亲切的感觉,我做过相关的工作(详见自主实现简易的ORM框架)。这个resultMap这种机制我亲手实现过,其追其根本就是反射机制

    当我看到mybatis和我以前的做法一样时,不禁狂喜,但是应该怎么测出来呢,得出它使用了反射机制这个结论呢?是个博弈猜测对话的过程,在此分享出来。

    一开始,我就把实体类的所有gettersetter方法全部删除,我没有反射执行的方法,我看你怎么反射。

    (1)删除所有getsetter,没有我看你怎么反射

    public class UserModel {
        private int id;
        private String name;
        private String password;
        
    }
    

    但是,结果还是出来了。从这可以分析出,mybatis框架的设计者考虑到有这种情况,没有相关set方法就自己创建相关set方法。佩服!那继续吃我下一招。

    (2)getseter设置为private,定义了设置为私有的我看你怎么反射

    很遗憾的是,这次mybatis框架设计者又赢了。依然可以执行出结果。从这明白了,反射存在setAccessable这种黑科技,priavte修饰符在这都没用。

    (3)实属无奈,最后想到小黄鸭调试法

    直接给setgettet方法里面加输出语句,看他是否输出,从此判断是否使用了反射机制。

    public class UserModel {
        private int id;
        private String name;
        private String password;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            System.out.println("setId反射执行了");
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            System.out.println("setName反射执行了");
            this.name = name;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            System.out.println("setPassword反射执行了");
            this.password = password;
        }
    }
    

    答案是令人满意的,确实输出了,也直接证明了resultMap是使用反射机制实现的,和以前的我做的ORM框架类似。

    这只是resultMap的基本用法,用来映射简单的字段和属性。但我们知道一个数据库一定是复杂的,类的属性也不简单的是八大基本类型,肯定有类类型。所以resultMap后面引入了association等其他标签,这就是resultMap的高级用法了。但是,我只想究其本质的说,根本不需要怕什么高级用法,这个XML的resultMap的标签只是在描述表和类之间的不同的部分,心中有了映像图,不论是写还是读,你都可以很快明白association就是描述来自于其他表的字段和属性之间的映射关系,追溯其里面的标签还是在描述字段和属性的映射关系,我们此时就可以和我做的框架一样把这种映射关系提取出来形成一个类PropertyColumnDefintion,这就是我的ORM框架的做法了,我不知道Mybatis底层是怎样做的,但我认为我这方便理解面向对象思想。

    总结:mybatis对于属性和字段名不一样有两种解法。这两者分别就是数据库层面上和Java层面上,对于数据库层面上的修改可以通过别名解决,而在Java层面上就要借助反射机制了。

    同时,追求解答的过程是有趣并痛苦的。从这可以看出来Mybatis框架鲁棒性是多么的强啊!膜拜

    七、日志

    如果数据库操作,出现异常,我们需要排错。日志就是最好的助手!

    曾经:sout(小黄鸭测试法)、debug

    现在:日志工厂。

    • LOG4J【掌握】
    • STDOUT_LOGGING 【掌握】

    在Mybatis中具体使用哪一个日志实现,在设置中设定!

    STDOUT_LOGGING 标准日志输出

    在mybatis核心配置文件中,配置日志!

        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    

    Log4j

    什么是Log4j

    • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
    • 我们也可以控制每一条日志的输出格式;
    • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
    • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
    1. pom下先导入log4j包
    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
    
    1. log4j的相关配置,放在resources下 log4j.properties
    #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和fiLe的定义在下面的代码
    1og4j.rootLogger=DEBUG, console,file
    #控制台输出的相关设置
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    1og4j.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
    1og4j.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.sq1=DEBUG
    1og4j.logger.java.sq1.statement=DEBUG
    log4j.logger.java.sq1.ResultSet=DEBUG
    log4j.logger.java.sq1.PreparedStatement=DEBUG
    
    

    3 . 配置log4j为日志的实现

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    

    Log4j类中使用

    1. 在要使用Log4j的类中,导入包import org.apache.log4j.Logger;

    2. 日志对象,参数为当前类的class

    static Logger logger = Logger.getLogger(UserDaoTest.class);
    
    1. 日志级别
    logger.info("info:进入了testLog4j");
    logger.debug("debug:进入了testLog4j");
    logger.error("error:进入了testLog4j");
    

    理解打包后的项目经历了什么

      在日志学习这里遇到找不到相关资源问题,经过网上搜索解决了,并且深刻的理解,打包后的项目都发生了什么?

      首先,一个Mavne项目的目录结构从src开始分析,分为两大部分main和test。main下的java(蓝色标注):该目录下是我们写的.java后缀结尾的源代码,resources(黄色金币标注):该目录下是我们项目所需要的xml、properties文件。test下就是测试的东西,需要程序员自己进行和main形成一个镜像。

      一旦Maven项目运行起来了,它就进行了打包。main和test分别形成了classes和test-classes目录。classes目录展开来看和java目录有着一模一样的结构,文件也都一样只不过名称变成了.class的字节码文件。我们以后为了保护源码传给别人的就是打包后的classes文件;同时,还发现并没有resources目录了,而原本resources目录下的所有文件直接附着在了classes文件下,这就是为什么我们经过打包后,每次访问资源文件都不需要加路径,直接进行访问,因为程序当前就在classes目录下待着,它此时就是以这里为根据,访问其他相对位置的地方,这个初始的路径我们有个重要的称谓classPath,classPath就是我们程序员编写代码前最开始的路径,也是打包后的class路径,resources目录随着打包自动合并了。Test也是如此。

    InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
    //这就是为什么我们直接可以访问资源文件前不需要加任何路径的原因,因为当前就在classPath下
    //以后所有去访问所有路径,都站在该classPath进行相对定位
    
    
    Thread.currentThread().getContextClassLoader().getResource("")
    //而这句话,根据classLoad就能得到当前程序运行的绝对路径(带盘符的那种),就知道当前在哪个物理上真真实实的路径了
    
    

    所以我们,以后只提classPath这个概念。普通Java程序的src就是classPath,web项目的src也是classPath,只要开始编代码的都是classPath,resources目录随着打包自动合并,其他路径的文件根据当前classPath进行相对定位!

    八、分页

    思考:为什么要分页?

    • 减少数据的处理量
    • 一个页面显示不下

    7.1、使用Limit分页

    分页SQL语句 limit

    select * from mybatis.user limit startIndex,pageSize;
    #从第几个下标(startIndex)开始,显示几个(pageSize)
    select * from mybatis.user limit 3; 
    #[0,3]
    

    使用Mybatis实现分页,核心SQL

    1.接口

    List<UserModel> getUserListLimit(Map<String, Integer> paraMap);
    

    2.绑定一个mapper.xml

    <mapper namespace="com.kuang.dao.IUserDaoFour">
        <resultMap id="getUserListLimitPropertyColumnMapping" type="com.kuang.pojo.UserModel">
            <result property="password" column="pwd"/>
        </resultMap>
    
        <select id="getUserListLimit" parameterType="map" resultMap="getUserListLimitPropertyColumnMapping">
            select * from mybatis.user limit  #{startIndex},#{pageSize}
        </select>
    </mapper>
    

    3.测试

        public void test() {
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            Map<String,Integer> paraMap = new HashMap<>();
            paraMap.put("startIndex", 0);
            paraMap.put("pageSize", 3);
            IUserDaoFour iUserDaoFour = sqlSession.getMapper(IUserDaoFour.class);
            List<UserModel> userListLimit = iUserDaoFour.getUserListLimit(paraMap);
            for (UserModel userModel : userListLimit) {
                System.out.println(userModel);
            }
            sqlSession.commit();
            sqlSession.close();
        }
    

    RowBounds分页

    过时了,不建议学习。

    分页插件

    pageHelper

    九、使用注解开发

    9.1、面向接口编程

    -大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
    -根本原因∶解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好
    -在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
    -而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

    关于接口的理解

    -接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。

    -接口的本身反映了系统设计人员对系统的抽象理解。
    -接口应有两类:
    -第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);-

    -第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface) ;-

    -一个体有可能有多个抽象面。抽象体与抽象面是有区别的。

    三个面向区别

    -面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法.

    -面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现.

    -接口设计与非接口设计是针对复用技术而言的,与面向对象〈过程)不是一个问题.更多的体现就是对系统整体的架构

    我理解的面向接口编程:接口是由富有经验的架构师设计的,一个优秀的架构师可以设计十分实用且复用次数多的框架。面向接口编程在工程上就是为了省钱,加快开发效率。试问有了Java之后,你给一个学校开发一套系统,完成了然后再给另一个学校开发他们的系统,难道还需要从头开始吗?这是不必要的,因此有了框架的概念,框架相当于人的骨头,肉随着骨头去长,也就是说其他锦上添花的需求不应该在框架内考虑,框架只做主体系统的内部结构。框架按层结构来搭建,Dao层只干Dao层的事,Service只做自己该干的事。这一层的接口只做自己接口的事。

    对接口有了更深刻的思考,即插即用,我只是定个方向,具体怎么实现接口不管,你给我注入不同的实现类,该接口就可以进行复用了。

    9.2、使用注解开发

    1. 注解在接口上实现(接口实现了impl,就一个简单SQL)
        @Select("select * from mybatis.user")
        List<UserModel> getUserList();
    
    1. 需要在核心配置文件中绑定接口!
        <mappers>
            <!--<mapper resource="com/kuang/dao/UserDaoFourMapper.xml"></mapper>-->
            <mapper class="com.kuang.dao.IUserDaoFour"/>
        <!--  Resource绑定时使用 / 访问文件,class就用.访问java文件  -->
        </mappers>
    
    1. 测试

    本质:反射机制和动态代理机制

    9.3、CRUD

    编写接口,增加注解

    @Select("select * from user")
    List<User> getUsers();
    
    //方法存在多个参数,所有的参数前面必须加@Param("id")注解
    @Select("select * from user where id = ${id}")
    User getUserById(@Param("id") int id);
    
    @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{password})")
    int addUser(User user);
    
    @Update("update user set name=#{name},pwd=#{password} where id = #{id}")
    int updateUser(User user);
    
    

    测试类

    【注意,必须将接口注册绑定到核心配置文件中】

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        IUserDaoFour mapper = sqlSession.getMapper(UserMapper.class);
    
        mapper.updateUser(new User(98, "sino", "abcdef"));
        sqlSession.commit();//不加,数据库不会有
        sqlSession.close();
    }
    
    

    关于@Param("")注解

    • 基本类型的参数或者String类型,需要加上 快一点
    • 引用类型不需要加(类类型映射不到)
    • 如果只有一个基本类型的话,可以忽略(底层根据下标找的),建议加上。
    • 在SQL中引用的就是@Param(“uid”)中设定的属性名

    #{}(防止SQL注入), ${}(可以拼接,导致SQL注入)

    9.4、Lombok

    没有进行学习,getsetter写起来很快的,没必要让别人帮你做。同时getsetter才是一个面向对象的灵魂(封装思想)所在!而且,如果你想要自己千奇百怪的pojo输出格式,就需要自己写toString方法,别什么都依赖别人帮你写。

    十、多对一(association)

    ER图

    多对一:

    在这里插入图片描述

    • 多个学生,对应一个老师
    • 对于学生这边而言, 关联, 多个学生,关联一个老师【多对一】
    • 对于老师而言,集合, 一个老师有很多学生【一对多】

    数据库图

    在这里插入图片描述

    所需要的数据库:

    CREATE TABLE `teacher`(
      `id` INT(20) NOT NULL,
      `name` VARCHAR(30) DEFAULT NULL,
      PRIMARY KEY(`id`)
    )ENGINE=INNODB DEFAULT CHARSET=utf8;
    
    INSERT INTO `teacher`(`id`,`name`) VALUES
    (1,'朱老师');
    INSERT INTO `teacher`(`id`,`name`) VALUES
    (2,'狂老师');
    
    CREATE TABLE `student`(
      `id` INT(20) NOT NULL,
      `name` VARCHAR(30) DEFAULT NULL,
      `teacher_id` INT(10) DEFAULT NULL,
      PRIMARY KEY(`id`),
      KEY `fktid` (`teacher_id`),
      CONSTRAINT `fktid` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)
    )ENGINE=INNODB DEFAULT CHARSET=utf8;
    
    
    INSERT INTO `student`(`id`,`name`,`teacher_id`) VALUES(1,'小明',1);
    INSERT INTO `student`(`id`,`name`,`teacher_id`) VALUES(2,'小红',2);
    INSERT INTO `student`(`id`,`name`,`teacher_id`) VALUES(3,'小张',1);
    INSERT INTO `student`(`id`,`name`,`teacher_id`) VALUES(4,'小李',2);
    INSERT INTO `student`(`id`,`name`,`teacher_id`) VALUES(5,'小王',1);
    

    建议一步步执行,否则会出现表还没建立,就先插入数据导致错误了。

    工程上还是建议不要建立外键,这里只是为了举例子才设置外键。

    建立实体类

    TeacherModel

    public class TeacherModel {
        private int id;
        private String name;
    
        //getset toString来一套
    }
    

    StudentModel

    public class StudentModel {
        private int id;
        private String name;
        //private int teacherId; 考虑再三,不需要
        private TeacherModel teacherModel;
    
        //get set toString
    }
    

    这个teacherId,到底在不在StudenModel里有以下的考虑。

    teacherId存在:

    优点:以后得到一个学生的实例(studentmodel),可以直接根据它蕴藏的tid查到它的老师(后面发现好像teacher就表示了,teacherId真的没有存在必要了,立刻删)

    缺点:数据冗余,teacherId与teacher表达意思一样,数据冗余。

    在java的世界里,teacher就是teacher,它也是个实体类,我根本不管你在数据库的编号是啥,我只只知道student有teacher这个属性。所以 int teacherId没必要。 或者是,可以写这个teacherId,不过不对外显示,get方法包权限,set方法包权限,只在内部用,对外不显示。

    从这明白了,java是java的世界,数据库是数据库的世界,我们俩要的不一样,表示也就不一样。

    建立接口

    public interface IStudentDao {
        
        List<StudentModel> getStudentList();
    }
    

    建立接口的实现XML文件

    解法一:按照结果嵌套查询(连表查询,重要需掌握)

    StudentDaoMapper.xml

    <mapper namespace="com.kuang.dao.IStudentDao">
    
        <select id="getStudentList" resultMap="getStudentListPropertyColumnMapping">
            select s.id as sid,s.name as sname,s.teacher_id as tid,t.name as tname
            from student as s,teacher as t where s.teacher_id = t.id
        </select>
    
        <resultMap id="getStudentListPropertyColumnMapping" type="com.kuang.pojo.StudentModel">
            <!--只写当前表与pojo类属性不同-->
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <!--复杂的属性需要association再深入-->
            <association property="teacherModel" javaType="com.kuang.pojo.TeacherModel">
                <result property="id" column="tid"/><!--没有这句话,teacher注入不完整-->
                <result property="name" column="tname"/>
            </association>
        </resultMap>
        
    </mapper>
    

    这里最重要的就是写SQL语句了,在这我也彻底明白了SQL语句,下面总结下。

    select语句主体

    SELECT (查出来形成新表的列名,强烈建议用as写好新表的列名) FROM (从哪几张表,建议也用as起别名,方便区分是哪一个表的列) WHERE (条件,不加就会变成笛卡尔积的形式)

    写Select语句就先写主体,SELECT … FROM … WHERE,然后根据需求去填充。(别名用as明示,别只写个空格)

    select s.id as sid,s.name as sname,s.teacher_id as tid,t.name as tname
    from student as s,teacher as t where s.teacher_id = t.id
    

    联表查询的SQL语句就很好写和分析了。上面的SQL语句代表从student表(别名为s)和teacher表(别名为t),形成结果新表sid列是student表的id;新表sname列是student表的name;新表tid列是student表的teacher_id;新表tname是teacher表的name;条件为student表的teacher_id与teacher表的id相等。

    起别名的原因是:经过select查询形成的新表的新列名就是按照别名走的,如果没设置就按源表走;同时设置了别名,mybtatis写参数也就按照新表走了。

    在mybatis核心配置XML文件进行注册

        <mappers>
            <mapper resource="com/kuang/dao/StudentDaoMapper.xml"/>
        </mappers>
    

    测试,成功。

    解法二:按照查询嵌套处理(子查询,复杂不建议)

    1. 查询所有学生的信息
    2. 根据查询出来的学生的tid,寻找对应的老师! 子查询

    StudentDaoMapper.xml

        <select id="getStudentListOne" resultMap="getStudentListOnePropertyColumnMapping">
            select * from student
            # 直接查全表
        </select>
        
        <resultMap id="getStudentListOnePropertyColumnMapping" type="com.kuang.pojo.StudentModel">
            <association property="teacherModel" column="teacher_id" javaType="com.kuang.pojo.TeacherModel" select="exSelect"/>
            <!--  再多个查询  -->
        </resultMap>
    
        <select id="exSelect" resultType="com.kuang.pojo.TeacherModel">
            select * from teacher where id = #{id}
        </select>
    

    在mybatis核心配置XML文件进行注册;测试,也成功。

    但还是建议使用连表查询,构造SQL简单且易懂。

    连表查询构建的SQL直接可以在数据库的控制台进行输入,然后看结果,而子查询不行,子查询还牵扯参数传递,所以复杂不好理解和调试。

    十一、一对多(collection)

    比如:一个老师拥有多个学生!

    对于老师而言,就是一对多的关系

    实体类

    public class TeacherModel {
        private int id;
        private String name;
        private List<StudentModel> studentList;
    }
    

    接口

    public interface ITeacherDao {
    
        TeacherModel getTeacherById(@Param("teacherId") int id);
    }
    

    建立接口的实现XML文件

    TeacherDaoMapper.xml

    <mapper namespace="com.kuang.dao.ITeacherDao">
    
        <select id="getTeacherById" resultMap="getTeacherByIdPropertyColumnMapping">
            SELECT s.id AS sid, s.name AS sname, t.name AS tname, t.id AS tid
             FROM student AS s, teacher AS t
             WHERE s.teacher_id = t.id AND t.id = #{teacherId}
        </select>
    
        <resultMap id="getTeacherByIdPropertyColumnMapping" type="com.kuang.pojo.TeacherModel">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
            <collection property="studentList" ofType="com.kuang.pojo.StudentModel">
                <result property="id" column="sid"></result>
                <result property="name" column="sname"></result>
            </collection>
        </resultMap>
    
    </mapper>
    

    去mybatis核心配置文件进行注册,测试ok。

    只写了连表查询,子查询就不写了,难度大且不易懂。

    小结

    1. 关联 - association 【多对一】
    2. 集合 - collection 【一对多】
    3. javaType:用来指定实体类中的属性的类型
    4. ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!

    注意点:

    • 保证SQL的可读性,进来保证通俗易懂
    • 注意一对多和多对一,属性名和字段的问题!
    • 如果问题不好排查错误,可以使用日志

    慢SQL 1s 1000s的差距 学习了sql索引知识后,把我们现在写的sql放在一边,参照着写。

    十二、动态SQL

    什么动态SQL:动态SQL就是指根据不同的条件生成不同的的SQL语句

    if

    <select id="queryBlogIF" parameterType="map" resultType="Blog">
        select *
        from mybatis.blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </select>
    
    

    where 1 = 1这个是为了where语句必须出现,但不知道后面是否满足条件。因此写个1 = 1。1=1 永真, 1<>1 永假。where 1<>1 这句查询出来的是 只要表结构不要表数据。

    choose (when, otherwise)形如switch语句

    <select id="queryBlogIF" parameterType="map" resultType="Blog">
        select * from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    title = #{title}
                </when>
                <when test="author != null">
                    and author = #{author}
                </when>
                <otherwise>
                    and views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>
    
    

    这里没有再使用where 1 = 1了,而使用了where标签。where标签,可以让SQL字符串拼接正确。

    有了where标签就不建议使用where 1=1了。where 1=1会导致表中的数据索引失效。

    所谓的动态SQL,本质还是SQL语句,只是可以在SQL层面,去执行一个逻辑代码

    SQL片段和foreach操作就不涉及了。

    动态SQL之我见

    怎么说呢,我认为理解并且会写最简单if就行了,动态SQL就是在拼接SQL字符串,mybatis就是操作数据库的框架,按照分离原则,数据库只管数据库的操作,少引入逻辑操作,引入个if就不错了。没有动态SQL,你可以一直划分细颗粒度的DAO操作,写的越简单越基础的方法,粒度越小,复用性越高,可以称为元操作吧。

    十三、缓存

      缓存(Cache,kashi,以前一直读错kachi纠正),这是一个很重要的概念。缓存对mybatis优化很起作用,缓存说白了就是提高查询效率。

    在这里插入图片描述

      最开始,单服务器,少量用户向服务器进行请求资源,服务器只负责和客户连接,资源文件肯定不存在服务器上,而放在数据库上,服务器分析客户的请求,然后从数据库取得相关数据再返还,早期就是这样的单线;

      而随着网络越来越发达,用户数量激增,传统的单个服务器承受不了巨大的压力,因此就需要多个服务器来进行处理,这些服务器可以跨地域设置以满足不同地区用户的体验感,快速响应用户请求。

      虽说请求由于多个服务器所以处理速度快了,但是真正的资源要去数据库拿;而数据库其本质也是个服务器,其最主要工作就是读和写。压力有都转移到数据库这里了。应该怎么办呢?架构中没有什么是加一层解决不了的,分析读操作和写操作应该是独立的,所以加一层memoryCache缓存,memoryCache存储常用的数据库资源,实现读写分离,读操作先读memoryCache读,没有再去数据库读,而写的压力全给数据库。

      如果还嫌处理速度不够快,那么就把数据库也弄成多个,这样可以分担压力。但是多个数据库就要考虑数据一致性的问题了。如何保证呢?主从复制!

    从上面发展历史中,你也就能明白缓存就是一个存放常用数据的仓库(池子),方便用户快速得到。

    Mybatis中的缓存也是如此意思

    1.什么是缓存[ Cache ]

    • 存在内存中的临时数据。
    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

    2.为什么使用缓存?

    • 减少和数据库的交互次数,减少系统开销,提高系统效率。

    3.什么样的数据能使用缓存?

    • 经常查询并且不经常改变的数据。

    Mybatis缓存

    • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
    • MyBatis系统中默认定义了两级缓存:一级缓存二级缓存
      • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)。二级缓存需要手动开启和配置,他是基于namespace(一个接口的mapper.xml)级别的缓存。
      • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

    Mybatis一级缓存

    mybatis一级缓存又称本地缓存。

    • 一级缓存默认打开

    • 一级缓存生命周期是一次会话(一次打开和关闭sqlSession),此会话期间有效

        public void test() {
            SqlSession sqlSeeion = MybatisUtil.getSqlSeeion();  //openSession
    
            //一级缓存仅在此之间有效
    
            sqlSeeion.commit();
            sqlSeeion.close();
        }
    

    (1)与数据库同一次会话期间查询到的数据会放在本地缓存中。

    (2)以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

    • 例子证明一级缓存存在
        @Test
        public void test() {
            SqlSession sqlSeeion = MybatisUtil.getSqlSeeion();
    
            IUserDaoFive mapper = sqlSeeion.getMapper(IUserDaoFive.class);
            UserModelFive user = mapper.getUserById(1);
    
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            UserModelFive anotherUser = mapper.getUserById(1);
    
            System.out.println("他俩地址值相同吗?" + (user == anotherUser));    //true
    
            sqlSeeion.commit();
            sqlSeeion.close();
        }
    

    输出为true,查询同一个id,一开始我以为底层肯定是使用反射机制new了一个新的pojo对象,而此时==为true,说明地址值相同,就说明此时这两个对象是一样的,这就证明了一级缓存的存在。同时日志信息可以看到相关SQL只执行了一次,说明第二次对象就是从一级缓存取的。

    • 一级缓存失效的情况

    (1)增删改(insert,update,delete)操作,可能会改变原来的数据,为了确保数据实时,所以会刷新一级缓存

    (2)查询不同的Mapper.xml(也就是说查了另一个接口的实现XML文件,从这知道同一个sqlsession下的不同mapper的缓存是各自的,后证实为不同的mapper.xml对应不同的二级缓存,后面学到可以mapper.xml通过引用传递二级缓存)

        @Test
        public void testMapperOneCache() {
            SqlSession sqlSeeion = MybatisUtil.getSqlSeeion();
    
            IUserDaoFive mapperOne = sqlSeeion.getMapper(IUserDaoFive.class);
            UserModelFive userOne = mapperOne.getUserById(1);
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            IUserDaoSix mapperTwo = sqlSeeion.getMapper(IUserDaoSix.class);
            UserModelFive userTwo = mapperTwo.getUserByUserId(1);
    
    
            System.out.println("地址值相同吗?" + (userOne == userTwo));
            //false。说明不同的mapper.xml有自己不同的一级缓存(后证实为不同的mapper.xml对应不同的二级缓存)
    
            sqlSeeion.commit();
            sqlSeeion.close();
        }
    

    (3)手动清理缓存

    sqlSeeion.clearCache();
    

    Mybatis二级缓存

    • 二级缓存也叫全局缓存,一级缓存作用域太低了(一次sqlseesion完就关闭),所以诞生了二级缓存
    • 基于namespace级别的缓存,一个名称空间,一个mapper.xml对应一个二级缓存;
    • 工作机制
      • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
      • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
      • 新的会话查询信息,就可以从二级缓存中获取内容;
      • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

    使用步骤

    • 前提条件一:在核心配置文件显示的开启全局缓存
        <settings>
            <setting name="cacheEnabled" value="true"/>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    
    • 前提条件二:在当前Mapper.xml中使用二级缓存开启
        <!--当前mapper.xml里开启二级缓存-->
        <!--<cache/>  简单一句话就开启了,下面是还可以加参数-->
        <cache
                eviction="FIFO"
                flushInterval="60000"
                size="512"
                readOnly="true"/>
    
    • 所有的数据都会先放在一级缓存中,只有会话提交(sqlSeeion.commit()),或者关闭(sqlSeeion.close())的时候,才会转存到二级缓存中!

    • 开启上面两个条件后,二级缓存就生效了。当一级缓存关闭(sqlsession进行close后)时,同一mapper.xml下查询的对象会放在二级缓存中;不同的mapper.xml有自己独有的二级缓存。

        @Test
        public void testTwoCache() {
            SqlSession sqlSeeion = MybatisUtil.getSqlSeeion();
    
            IUserDaoFive mapper = sqlSeeion.getMapper(IUserDaoFive.class);
            UserModelFive user = mapper.getUserById(1);
            sqlSeeion.commit();
            sqlSeeion.close();
    
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            SqlSession sqlSeeion1 = MybatisUtil.getSqlSeeion();
    
            IUserDaoFive mapper1 = sqlSeeion1.getMapper(IUserDaoFive.class);
            UserModelFive user1 = mapper1.getUserById(1);
    
            sqlSeeion1.commit();
            sqlSeeion1.close();
    
    
            System.out.println("地址值相同吗?" + (user == user1));
            //true
            //1.核心文件开启显示开启缓存    <setting name="cacheEnabled" value="false"/>
            //2.mapper.xml定义缓存   <cache/>
            //cache没有readOnly="true",会报未序列化异常,和流有关系
        }
    
    
    • 不同mapper.xml引用别的mapper.xml的缓存
        @Test
        public void testMapperMoveStore() {
    
            SqlSession sqlSeeion = MybatisUtil.getSqlSeeion();
    
            IUserDaoFive mapper = sqlSeeion.getMapper(IUserDaoFive.class);
            UserModelFive user = mapper.getUserById(1);
    
            sqlSeeion.commit();
            sqlSeeion.close();
    
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            SqlSession sqlSeeion1 = MybatisUtil.getSqlSeeion();
    
            IUserDaoSix mapper1 = sqlSeeion1.getMapper(IUserDaoSix.class);
            UserModelFive user1 = mapper1.getUserByUserId(1);
    
            sqlSeeion1.commit();
            sqlSeeion1.close();
    
            System.out.println("不同mapper的二级缓存可以引用吗?" + (user == user1));
            //true。探究过程很有意思
        }
    
        <!--<cache/>--> <!--不使用自己的二级缓存池,而引用别的mapper.xml所对应接口的二级缓存池-->
        <cache-ref namespace="com.kuang.dao.IUserDaoFive"/>
    

    这里试了半天都是false,心态都崩了,和官方文档说的cache-ref不一样啊。在崩溃之际,网上搜索资料,终于解开谜题。参考了这位大佬的博文cache-ref。从中明白了cache是一个实例对象,不能既引入<cache/>,还引入<cache-ref/>;解析<cache/>结点,Mapper为自己创建一个缓存实例不再引用<cache-ref/>的缓存实例;也就是说一个mapper要么定义自己的二级缓存,要么引用别人的二级缓存,只能用一个池子。

    缓存原理映像图

    在这里插入图片描述

    自定义缓存

    当然可以使用自己自定义的缓存,我们先来看org.apache.ibatis.cache.Cache接口。

    package org.apache.ibatis.cache;
    
    import java.util.concurrent.locks.ReadWriteLock;
    
    public interface Cache {
    
      String getId();
    
      void putObject(Object key, Object value);
    
      Object getObject(Object key);
    
      Object removeObject(Object key);
    
      void clear();
    
      int getSize();
    
      default ReadWriteLock getReadWriteLock() {
        return null;
      }
    
    }
    
    

    你要实现自定义缓存就要实现该接口,完成其规定的所有方法。

    从这里明白了。实际上,设计一个接口,提出这些方法就是设计一种策略!规定你必须完成什么,后面的实现该接口的实现类是策略的具体实现了。

    然后相关mapper.xml导入自定义缓存就行了

    <cache type="com.domain.something.MyCache"/>
    

    工作一般在Redis(已经做到极致了)数据库来做缓存! K-V键值对的形式。都以K-V存储,直接取,直接放。这个我们到后面再学习。

    缓存之我见

    缓存落到最后都是为了提高查询效率。

    一级缓存其作用域就是随着sqlSeesion生死,仅在同一个sqlSession包裹下有效,不同的sqlSession有自己不同的一级缓存。

    二级缓存前提条件需要进行核心配置文件的显示开启,还需要在mapper.xml下开启cache标签。所有的数据都会先放在一级缓存中,只有会话提交(sqlSeeion.commit()),或者关闭(sqlSeeion.close())的时候,才会转存到二级缓存中!二级缓存的作用域就是一个mapper.xml下的,不同的mapper.xml有自己不同的二级缓存。随着一级缓存的关闭,相同mapper.xml查询的对象就会转存到同一个二级缓存下,不同mapper.xml查询到的对象会放在不同的二级缓存下。不同的mapper.xml要么使用自己的二级缓存池,要么引用别的mapper.xml的二级缓存池。

    展开全文
  • mybatis框架学习

    2021-04-17 19:13:29
    标题:mybatis框架学习 学习内容: 1、写一个简单的mybatis程序 2、增删改查 3、Map查询 4、配置—属性优化,别名优化,映射器说明 5、作用域与生命周期 6、ResultMap结果集映射和使用注解简介 7、缓存 内容详情: ...
  • MyBatis 环境: JDK1.8 Mysql5.7 Maven3.6.1 IDEA 回顾: ...SSM框架:配置文件的。...MyBatis 是一款优秀的持久层框架(Dao层) 它支持自定义 SQL、存储过程以及高级映射。 MyBatis 免除了几乎所有的 JDBC
  • (二)创建学生实体类 (三)创建班级实体类 四、创建班级映射器配置文件 五、修改MyBatis配置文件 六、定义班级映射接口ClazzMapper 七、创建测试类TestClazzMapper (一)运行测试方法testFindById(),查看结果 ...
  • MyBatis框架学习笔记

    2021-09-03 11:15:08
    文章目录全部学习笔记的思维脑图一、MyBatis框架概述二、MyBatis框架快速入门三、MyBatis框架动态代理及其参数的传入四、MyBatis框架输出结果五、MyBatis动态SQL六、MyBatis配置文件PageHelper——MyBatis通用分页...
  • 学习MyBatis之前,我们需要先熟悉下在软件开发中用到的 框架 的概念。 1.1 什么是框架 软件框架(software framework),通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件...
  • MyBatis框架学习笔记04:利用MyBatis实现条件查询 一、对学生表实现条件查询 (一)创建学生映射器配置文件 在resources/mapper目录里创建学生映射器配置文件 - StudentMapper.xml <?xml version="1.0" encoding...
  • MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan ...
  • MyBatis框架学习笔记03

    2021-03-15 08:12:08
    MyBatis框架学习笔记03:利用MyBatis实现关联查询 一、创建数据库表 (一)创建教师表 执行SQL语句,创建教师表t_teacher CREATE TABLE `t_teacher` ( `t_id` int(11) NOT NULL AUTO_INCREMENT, `t_name` varchar(20...
  • mybatis文档 mybatis3版本的源码–>https://github.com/mybatis/mybatis-3/releases 或点击–>mybatis3源码 文章目录1.什么是mybatis2.基础搭建使用(1)添加相关maven依赖(2)创建用户实体类User(3)创建核心...
  • mybatis框架学习总结第一天 快速入门 pojo(方法自添) package com.itheima.domain; import java.io.Serializable; public class User implements Serializable { private Integer id; private String username...
  • 文章目录一、什么是MyBatis(一)MyBatis概述(二)ORM工具的基本思想二、创建数据库与表1、在Navicat里创建MySQL数据库testdb2、创建用户表 - t_user3、插入若干条记录三、案例演示 - MyBatisDemo(一)创建Maven...
  • Mybatis框架学习01

    2021-05-15 21:21:31
    Mybatis 框架基于idea的maven环境搭建前言mybatis的依赖以及其他所需要的依赖引用properties文件配置合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的...
  • Mybatis框架学习笔记

    千次阅读 多人点赞 2021-03-17 01:03:18
    学习完了雷丰阳老师视频教程的Mybatis,记录一下。 mybatis基础 即ibatis3.0(源于Apache)之后的版本 三层架构: 表现层—展示数据 业务层—处理业务需求 持久层—和数据库交互 -持久层技术解决方案 JDBC技术(最...
  • 查看学生表 三、创建与数据库表对应的实体类 (一)创建教师实体类 (二)创建学生实体类 (三)创建班级实体类 四、创建班级配置映射器 五、修改MyBatis配置文件 在配置里配置班级 教师 与学生实体类别名,以及班级...
  • mybatis框架学习笔记

    2021-01-14 10:13:31
    一、自定义持久框架笔记 1.传统jdbc存在问题解决思路分析 数据库配置信息存在硬编码 解决思路:采用配置文件 频繁创建释放数据库链接 解决思路:使用数据库连接池 sql语句、设置参数、封装返回结果存在硬编码 解决...
  • MyBatis框架学习笔记03:利用MyBatis实现关联查询 一、创建教师表 在Navicat Premium 12软件中的testdb数据库中新建一个教师表t_teacher 在教师表中插入三条记录 查看教师表记录 二、创建班级表 在Navicat ...
  • MyBatis框架学习01

    2021-03-03 16:26:10
    文章目录 一、创建数据库与表 二、案例演示MyBatis基本使用 (一)创建Maven项目 - MyBatisDemo (二)在pom文件里添加相应的依赖 (三)创建用户实体类 (四)创建用户实体关系映射配置文件 (五)创建MyBatis配置...
  • MyBatis框架学习2

    2021-03-08 10:32:40
    MyBatis框架学习2 1.学习目标 如果表的列名与实体的属性名不一致如何进行定义 添加按姓名查询用户记录功能 插入更新删除表记录 2.遇到的问题 存在一些不细心的问题导致代码报错,后续进行了修改就好了 ...
  • MyBatis 框架 第一章 框架的概述 1.三层架构 mvc:web开发中,使用mvc架构模式。 m:数据, v:视图, c:控制器。 ​ c控制器: 接收请求,调用service对象,显示请求的处理结果。 当前使用servlet作为控制器 ​ v...
  • MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan ...
  • MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 83,072
精华内容 33,228
关键字:

mybatis框架学习