【Java46】Mybatis:动态代理


1.dao层的CRUD操作:以前userdao都是用jdbc template实现,现在换成Mybatis,需要一个sqlsession对象

在这里插入图片描述

1.1 dao

在这里插入图片描述

package com.itheima.dao;
import com.itheima.domain.User;

public interface UserDao {
    
    
    public void addUser(User user);
    public void update(User user);
    public User findUserById(int id);
    public void deleteById(int id);
}
package com.itheima.dao.impl;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.apache.ibatis.session.SqlSession;

public class UserDaoImpl implements UserDao {
    
    
    private SqlSession sqlSession;  //sqlSession现在是空值,以前直接=new jdbctemplate...
 //现在不是new一下能搞定的,要1.获取资源,2.解析配置,3.创建工厂对象,4.sqlSession。如下通过构造传入。
    public void setSqlSession(SqlSession sqlSession) {
    
     //传递赋值,构造和set方法都可以
        this.sqlSession = sqlSession;
    }
    @Override
    public void addUser(User user) {
    
    
        sqlSession.update("UserDaoMapper.addUser",user); //ibatis会自动将user映射成sql需要的参数
    }
    @Override
    public void update(User user) {
    
    
        sqlSession.update("UserDaoMapper.update",user);
    }
    @Override
    public void deleteById(int id) {
    
    
        sqlSession.update("UserDaoMapper.deleteById",id);
    }
    @Override
    public User findUserById(int id) {
    
    
        User user = sqlSession.selectOne("UserDaoMapper.findUserById", id); //返回user对象
        return user;
    }
}

1.2 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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="UserMapper.xml"/>
        <mapper resource="UserDaoMapper.xml"></mapper>
    </mappers>
</configuration>

1.3 UserDaoMapper.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">

<mapper namespace="UserDaoMapper">
    <select id="findUserById" resultType="com.itheima.domain.User">
        select * from tb_user where id = #{id}
    </select>

    <insert id="addUser">                                    <!-- user对象的属性-->
        insert into tb_user(user_name,password,name) values(#{userName},#{password},#{name})
    </insert>

    <delete id="deleteById">
        delete from tb_user where id=#{id}
    </delete>

    <update id="update">
        update tb_user set age=#{age},sex=#{sex} where id = #{id}
    </update>
</mapper>

1.4 domain

在这里插入图片描述

package com.itheima.domain;
import java.util.Date;

public class User {
    
    
    private Long id;    
    private String userName; // 用户名    
    private String password; // 密码    
    private String name; // 姓名    
    private Integer age; // 年龄    
    private Integer sex; // 性别,1男性,2女性    
    private Date birthday; // 出生日期    
    private Date created; // 创建时间    
    private Date updated; // 更新时间
    public Long getId() {
    
    
        return id;
    }
    public void setId(Long id) {
    
    
        this.id = id;
    }
    public String getUserName() {
    
    
        return userName;
    }
    public void setUserName(String userName) {
    
    
        this.userName = userName;
    }
    public String getPassword() {
    
    
        return password;
    }
    public void setPassword(String password) {
    
    
        this.password = password;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public Integer getAge() {
    
    
        return age;
    }
    public void setAge(Integer age) {
    
    
        this.age = age;
    }
    public Integer getSex() {
    
    
        return sex;
    }
    public void setSex(Integer sex) {
    
    
        this.sex = sex;
    }
    public Date getBirthday() {
    
    
        return birthday;
    }
    public void setBirthday(Date birthday) {
    
    
        this.birthday = birthday;
    }
    public Date getCreated() {
    
    
        return created;
    }
    public void setCreated(Date created) {
    
    
        this.created = created;
    }
    public Date getUpdated() {
    
    
        return updated;
    }
    public void setUpdated(Date updated) {
    
    
        this.updated = updated;
    }
    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", birthday=" + birthday +
                ", created=" + created +
                ", updated=" + updated +
                '}';
    }
}

1.5 test

在这里插入图片描述
在这里插入图片描述
如上选中按ctrl+shift+t产生如下:
在这里插入图片描述

package com.itheima.dao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.domain.User;
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 org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import static org.junit.Assert.*;

public class UserDaoTest {
    
    
    private UserDaoImpl userDao = new UserDaoImpl();
    @Before
    public void setUp() throws Exception {
    
     //创建sqlSession        
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); //获取io流对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //工厂对象     
        SqlSession sqlSession = sqlSessionFactory.openSession(true); //true表示自动提交事务
        userDao.setSqlSession(sqlSession);
    }
    @Test
    public void addUser() {
    
    
        User user = new User();
        user.setPassword("123666");
        user.setName("王思聪1");
        user.setUserName("wangsicong1");
        userDao.addUser(user);
    }
    @Test
    public void update() {
    
    
        User user = new User();
        user.setId(10l);
        user.setAge(30);
        user.setSex(1);
        userDao.update(user);
    }
    @Test
    public void findUserById() {
    
    
        User user = userDao.findUserById(10);
        System.out.println(user);
    }
    @Test
    public void deleteById() {
    
    
        userDao.deleteById(10);
    }
}

如下或者在.openSession里写true。
在这里插入图片描述

2.动态代理Dao实现:userDao对象改为userMapper对象

发现每个dao层sqlSession.insert等每个方法底层都是update实现都是一样的,只是参数不一样,所以可以把方法都写一样。只有接口情况下,mybatis帮我们创造实现类UserDaoImpl即动态代理,调用mybatis方法创建的接口类型对象。

mybatis动态代理方式需要遵循以下约定即namespace和id限制
1.  一个接口对应一个mapper文件 【默认】
2. 映射文件中的命名空间(名称控制)与 接口的全路径 一致
3. 映射文件中的statement的Id与 接口的方法名 保持一致
4. 映射文件中的statement的ResultType必须和mapper接口方法的返回类型一致(即使不采用动态代理,也要一致)【默认】

如下2,3对应上面2,3。
在这里插入图片描述
如下dao文件夹名称换成mapper文件夹。
在这里插入图片描述

2.1 mapper

package com.itheima.mapper;
import com.itheima.domain.User;

public interface UserMapper {
    
    
    public User findUserById(int id);
    public void deleteById(int id);
}

2.2 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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>

2.3 UserMapper.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">
<mapper namespace="com.itheima.mapper.UserMapper">
    <!--
        mybatis动态代理开发重点规范:
            1 namespace必须和接口的全路径保证一致
            2 sql语句的id必须和方法名保证一致
     -->
    <select id="findUserById" resultType="com.itheima.domain.User">
        select * from tb_user where id = #{id}
    </select>
</mapper>

2.4 test

在这里插入图片描述
在这里插入图片描述

package com.itheima.mapper;
import com.itheima.domain.User;
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 org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import static org.junit.Assert.*;

public class UserMapperTest {
    
    
    private UserMapper userMapper; //声明但未new创建
    @Before
    public void setUp() throws Exception {
    
     //创建userMapper对象
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFacoty = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFacoty.openSession();
        userMapper = sqlSession.getMapper(UserMapper.class); //底层是动态代理(只有接口情况下,创建接口类对象)
    }
    @Test
    public void findUserById() {
    
     
        User user = userMapper.findUserById(1); //userMapper对象
        System.out.println(user);
    }
}

所以只需要一个UserMapper接口就行。
在这里插入图片描述

3.动态代理底层原理:接口名和方法名

package com.itheima.proxy;
import com.itheima.mapper.UserMapper;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MapperProxy {
    
     //工具类    
    public static UserMapper getProxyMapper(){
    
     //提供一个方法,创建接口对象的动态代理对象的
        /*
            参数1:类加载器,任意一个类加载器即可。
            参数2: 被代理对象UserMapper实现的接口。
            参数3:处理器
         */
        ClassLoader classLoader = UserMapper.class.getClassLoader();
        Class[] classes = new Class[1]; //只有一个UserMapper接口就可以
        classes[0]=UserMapper.class;
        UserMapper proxyUserMapper = (UserMapper) Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
    
    
            /**
             * @param proxy  代理对象本身,没用。
             * @param method 将要执行的方法
             * @param args  方法需要的参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                   
                //mybatis框架规范:1.namespace必须是接口的全限定名。2.statement的id就是接口的方法名。                                  
                String methodName = method.getName(); //获取将要执行的方法的名字
                String nameSpace = UserMapper.class.getName();
                String statementId= methodName;
                
                String sqlId = nameSpace+"."+statementId;
                System.out.println("将要执行的sql语句的唯一标识是:"+sqlId);
               // sqlSession.update(sqlId,args);
                return null;
            }
        });
        return  proxyUserMapper;
    }

    public static void main(String[] args) {
    
    
        UserMapper userMapper = getProxyMapper();
        userMapper.findUserById(1); 
        // userMapper.deleteById(1);  //运行的是invoke方法
    }
}

如上打印出如下就是UserMapper.xml中namespace.方法名。
在这里插入图片描述
如下所以mybatis要设计一套规范,让调用者遵循规范写。
在这里插入图片描述
如下日志:

package com.itheima.log4j;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class Log4jTest {
    
    
    private static Logger logger = LogManager.getLogger(Log4jTest.class);
    public static void main(String[] args) {
    
    
        /**
         *  日志从低到高6个级别,中间4个常见
         *      trace<    debug<warn<info<error   <fatal
         */
        logger.trace("trace");
        logger.debug("debug");
        logger.warn("warn");
        logger.info("info");
        logger.error("error");
    }
}

在这里插入图片描述
在这里插入图片描述
B站/知乎/微信公众号:码农编程录
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43435675/article/details/113863344