MyBatis系列第3篇:Mybatis使用详解(1)

为了方便查看mybatis运行过程中产生的日志,比如:执行的sql、sql的参数、sql的执行结果等等调试信息,我们需要引入日志框架的支持,logback是一个很好的日志框架,此处我们就使用这个

mybatis中集成logback步骤
  1. maven中引入logback支持

ch.qos.logback

logback-classic

1.2.3

  1. src/main/resources中创建logback.xml文件:
<?xml version="1.0" encoding="UTF-8"?>

%d{mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

logback.xml具体的写法不是本文讨论的范围,有兴趣的朋友可以去研究一下logback具体的用法。

上面xml中配置了com.javacode2018包中所有的类,使用logback输出日志的时候,debug级别及以上级别的日志会输出到控制台,方便我们查看。

写一个测试用例

chat02/src/test下创建一个类:

com.javacode2018.chat02.UserTest

内容如下:

package com.javacode2018.chat02;

import lombok.extern.slf4j.Slf4j;

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.IOException;

import java.io.InputStream;

@Slf4j

public class UserTest {

private SqlSessionFactory sqlSessionFactory;

@Before

public void before() throws IOException {

//指定mybatis全局配置文件

String resource = “mybatis-config.xml”;

//读取全局配置文件

InputStream inputStream = Resources.getResourceAsStream(resource);

//构建SqlSessionFactory对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

this.sqlSessionFactory = sqlSessionFactory;

}

@Test

public void sqlSession() {

SqlSession sqlSession = this.sqlSessionFactory.openSession();

log.info(“{}”, sqlSession);

}

}

上面代码中有个@Slf4j注解,这个是lombok提供的,可以在这个类中生成下面代码:

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserTest.class);

运行一下上面的用例:sqlSession方法,输出如下:

45:51.289 [main] INFO  com.javacode2018.chat02.UserTest - org.apache.ibatis.session.defaults.DefaultSqlSession@1f021e6c

使用SqlSesion执行sql操作

SqlSession常见的用法

SqlSession相当于一个连接,可以使用这个对象对db执行增删改查操作,操作完毕之后需要关闭,使用步骤:

1.获取SqlSession对象:通过该sqlSessionFactory.openSession方法获取SqlSession对象

2.对db进行操作:使用SqlSession对象进行db操作

3.关闭SqlSession对象:sqlSession.close();

常见的使用方式如下:

//获取SqlSession

SqlSession sqlSession = this.sqlSessionFactory.openSession();

try {

//执行业务操作,如:增删改查

} finally {

//关闭SqlSession

sqlSession.close();

}

上面我们将SqlSession的关闭放在finally块中,确保close()一定会执行。更简单的方式是使用java中的try()的方式,如下:

try (SqlSession sqlSession = this.sqlSessionFactory.openSession()😉 {

//执行业务操作,如:增删改查

}

新增操作

需求:传入UserModel对象,然后将这个对象的数据插入到t_user表中。

创建一个`UserModel`

新建一个com.javacode2018.chat02.UserModel类,代码如下:

package com.javacode2018.chat02;

import lombok.*;

/**

* 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!

*/

@Getter

@Setter

@NoArgsConstructor

@AllArgsConstructor

@Builder

@ToString

public class UserModel {

private Long id;

private String name;

private Integer age;

private Double salary;

private Integer sex;

}

这个类的字段和t_user表对应。

UserMapper.xml中定义插入操作

我们说过了,对t_user表的所有sql操作,我们都放在UserMapper.xml中,我们在UserMapper.xml中加入下面配置,使用insert元素定义插入操作:

<![CDATA[ INSERT INTO t_user (id,name,age,salary,sex) VALUES (#{id},#{name},#{age},#{salary},#{sex}) ]]>

insert元素用来定义了一个对db的insert操作

id:是这个操作的一个标识,一会通过mybatis执行操作的时候会通过这个namespace和id引用到这个insert操作,

parameterType:用来指定这个insert操作接受的参数的类型,可以是:各种javabean、map、list、collection类型的java对象,我们这个插入接受的是UserModel对象。

insert元素内部定义了具体的sql,可以看到是一个insert的sql,向t_user表插入数据。

需要插入的值从UserModel对象中获取,取UserModel对象的的字段,使用**#{字段}**这种格式可以获取到UserModel中字段的值。

调用SqlSession.insert方法执行插入操作

t_user插入的sql我们已经在UserMapper中写好,此时我们怎么调用呢?

需要调用SqlSession.insert方法:

int insert(String statement, Object parameter)

这个方法有2个参数:

statement:表示那个操作,值为Mapper xml的namespace.具体操作的id,如需要调用UserMapper.xml中的insertUser操作,这个值就是:

com.javacode2018.chat02.UserMapper.insertUser

parameter:insert操作的参数,和Mapper xml中的insert中的parameterType指定的类型一致。

返回值为插入的行数。

UserTest类中新增一个测试用例:

@Test

public void insertUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(false)😉 {

//创建UserModel对象

UserModel userModel = UserModel.builder().id(2L).name(“javacode2018”).age(30).salary(50000D).sex(1).build();

//执行插入操作

int result = sqlSession.insert(“com.javacode2018.chat02.UserMapper.insertUser”, userModel);

log.info(“插入影响行数:{}”, result);

//提交事务

sqlSession.commit();

}

}

运行输出如下:

01:46.683 [main] DEBUG c.j.chat02.UserMapper.insertUser - ==>  Preparing: INSERT INTO t_user (id,name,age,salary,sex) VALUES (?,?,?,?,?)

01:46.745 [main] DEBUG c.j.chat02.UserMapper.insertUser - ==> Parameters: 2(Long), javacode2018(String), 30(Integer), 50000.0(Double), 1(Integer)

01:46.751 [main] DEBUG c.j.chat02.UserMapper.insertUser - <==    Updates: 1

01:46.751 [main] INFO com.javacode2018.chat02.UserTest - 影响行数:1

输出中打印了详细的sql语句,以及sql的参数信息,可以看到Mapper xml中的#{}被替换为了?,这个使用到了jdbc中的PreparedStatement来对参数设置值。

输出中的第二行详细列出了参数的值以及每个值的类型。

第三行输出了insert的结果为1,表示插入成功了1行记录。

去db中看一下,如下,插入成功:

mysql> SELECT * FROM t_user;

±—±--------------±----±---------±----+

| id | name          | age | salary   | sex |

±—±--------------±----±---------±----+

|  1 | 路人甲Java    |  30 | 50000.00 |   1 |

±—±--------------±----±---------±----+

1 row in set (0.00 sec)

上面代码中创建SqlSession,我们使用的是sqlSessionFactory.openSession()创建的,这个方法创建的SqlSession,内部事务是非自动提交的方式,所以需要我们手动提交:

sqlSession.commit();

如果想自动提交事务,可以将上面的测试用例改成下面这样:

@Test

public void insertUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

//创建UserModel对象

UserModel userModel = UserModel.builder().id(1L).name(“路人甲Java”).age(30).salary(50000D).sex(1).build();

//执行插入操作

int result = sqlSession.insert(“com.javacode2018.chat02.UserMapper.insertUser”, userModel);

log.info(“影响行数:{}”, result);

}

}

上面在创建SqlSession的时候调用了sqlSessionFactory.openSession(true),指定事务为自动提交模式,所以最后我们不需要手动提交事务了。

更新操作

需求:传入UserModel对象,然后通过id更新数据。

UserMapper.xml中定义Update操作

使用update定义更新操作:

<![CDATA[ UPDATE t_user SET name = #{name},age = #{age},salary = #{salary},sex = #{sex} WHERE id = #{id} ]]>

写法和insert操作的写法类似,指定id标识、parameterType指定操作的参数类型,元素体中是具体的sql语句。

调用SqlSession.update方法执行更新操作

需要调用SqlSession.update方法:

int update(String statement, Object parameter)

这个方法有2个参数:

statement:表示哪个操作,值为Mapper xml的namespace.具体操作的id,如需要调用UserMapper.xml中的updateUser操作,这个值就是:

com.javacode2018.chat02.UserMapper.updateUser

parameter:update操作的参数,和Mapper xml中的update中的parameterType指定的类型一致。

返回值为update影响行数。

UserTest类中新增一个测试用例:

@Test

public void updateUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

//创建UserModel对象

UserModel userModel = UserModel.builder().id(1L).name(“路人甲Java,你好”).age(18).salary(5000D).sex(0).build();

//执行更新操作

int result = sqlSession.update(“com.javacode2018.chat02.UserMapper.updateUser”, userModel);

log.info(“影响行数:{}”, result);

}

}

运行输出:

14:09.051 [main] DEBUG c.j.chat02.UserMapper.updateUser - ==>  Preparing: UPDATE t_user SET name = ?,age = ?,salary = ?,sex = ? WHERE id = ?

14:09.095 [main] DEBUG c.j.chat02.UserMapper.updateUser - ==> Parameters: 路人甲Java,你好(String), 18(Integer), 5000.0(Double), 0(Integer), 1(Long)

14:09.100 [main] DEBUG c.j.chat02.UserMapper.updateUser - <==    Updates: 1

14:09.101 [main] INFO com.javacode2018.chat02.UserTest - 影响行数:1

db中去看一下:

mysql> SELECT * FROM t_user;

±—±-----------------------±----±---------±----+

| id | name                   | age | salary   | sex |

±—±-----------------------±----±---------±----+

|  1 | 路人甲Java,你好       |  18 |  5000.00 |   0 |

|  2 | javacode2018           |  30 | 50000.00 |   1 |

±—±-----------------------±----±---------±----+

2 rows in set (0.00 sec)

删除操作

需求:根据用户的id删除对应的用户记录

UserMapper.xml中定义Delete操作

使用update元素定义删除操作:

<![CDATA[ DELETE FROM t_user WHERE id = #{id} ]]>

写法和update操作的写法类似,指定id标识、parameterType指定操作的参数类型,用户id为Long类型的,元素体中是具体的delete语句。

调用SqlSession.update方法执行更新操作

需要调用SqlSession.delete方法:

int delete(String statement, Object parameter)

这个方法有2个参数:

statement:表示哪个操作,值为Mapper xml的namespace.具体操作的id,如需要调用UserMapper.xml中的deleteUser操作,这个值就是:

com.javacode2018.chat02.UserMapper.

parameter:delete操作的参数,和Mapper xml中的delete中的parameterType指定的类型一致。

返回值为delete影响行数。

UserTest类中新增一个测试用例:

@Test

public void deleteUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

//定义需要删除的用户id

Long userId = 1L;

//执行删除操作

int result = sqlSession.delete(“com.javacode2018.chat02.UserMapper.deleteUser”, userId);

log.info(“影响行数:{}”, result);

}

}

运行输出:

24:45.427 [main] DEBUG c.j.chat02.UserMapper.deleteUser - ==>  Preparing: DELETE FROM t_user WHERE id = ?

24:45.476 [main] DEBUG c.j.chat02.UserMapper.deleteUser - ==> Parameters: 1(Long)

24:45.485 [main] DEBUG c.j.chat02.UserMapper.deleteUser - <==    Updates: 1

24:45.485 [main] INFO com.javacode2018.chat02.UserTest - 影响行数:1

执行查询

需求:查询所有用户信息

UserMapper.xml中定义Select操作
<![CDATA[ SELECT * FROM t_user ]]>

写法和update操作的写法类似,指定id标识、parameterType指定操作的参数类型,resultType指定查询结果的类型,元素体中是具体的select语句。

调用SqlSession.select方法执行更新操作

UserTest添加一个用例:

@Test

public void getUserList() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

//执行查询操作

List userModelList = sqlSession.selectList(“com.javacode2018.chat02.UserMapper.getUserList”);

log.info(“结果:{}”, userModelList);

}

}

多插入几行,然后运行上面的用例,输出如下:

36:39.015 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==>  Preparing: SELECT * FROM t_user

36:39.048 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==> Parameters:

36:39.066 [main] DEBUG c.j.chat02.UserMapper.getUserList - <==      Total: 3

36:39.067 [main] INFO  com.javacode2018.chat02.UserTest - UserModel(id=2, name=javacode2018, age=30, salary=50000.0, sex=1)

36:39.069 [main] INFO  com.javacode2018.chat02.UserTest - UserModel(id=1575621274235, name=路人甲Java, age=30, salary=50000.0, sex=1)

36:39.069 [main] INFO  com.javacode2018.chat02.UserTest - UserModel(id=1575621329823, name=路人甲Java, age=30, salary=50000.0, sex=1)

Mapper接口的使用

为什么需要Mapper接口

上面我们讲解了对一个表的增删改查操作,都是通过调用SqlSession中的方法来完成的,大家再来看一下SqlSession接口中刚才用到的几个方法的定义:

int insert(String statement, Object parameter);

int update(String statement, Object parameter);

int delete(String statement, Object parameter);

 List selectList(String statement);

这些方法的特点我们来看一下:

  1. 调用这些方法,需要明确知道statement的值,statement的值为namespace.具体操作的id,这些需要打开Mapper xml中去查看了才知道,写起来不方便

  2. parameter参数都是Object类型的,我们根本不知道这个操作具体类型是什么,需要查看Mapper xml才知道,随便传递个值,可能类型不匹配,但是只有在运行的时候才知道有问题

  3. selectList方法返回的是一个泛型类型的,通过这个方法我们根本不知道返回的结果的具体类型,也需要去查看Mapper xml才知道

以上这几点使用都不是太方便,有什么方法能解决上面这些问题么?

有,这就是mybatis中的Mapper接口,我们可以定义一个interface,然后和Mapper xml关联起来,Mapper xml中的操作和Mapper接口中的方法会进行绑定,当我们调用Mapper接口的方法的时候,会间接调用到Mapper xml中的操作,接口的完整类名需要和Mapper xml中的namespace一致。

Mapper接口的用法(三步)
步骤1:定义Mapper接口

去看一下,UserMapper.xml中的namespace,是:

我们创建的接口完整的名称需要和上面的namespace的值一样,下面我们创建一个接口com.javacode2018.chat02.UserMapper,如下:

package com.javacode2018.chat02;

/**

* 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!

*/

public interface UserMapper {

}

UserMapper.xml中有4个操作,我们需要在UserMapper接口中也定义4个操作,和UserMapper.xml的4个操作对应,如下:

package com.javacode2018.chat02;

import java.util.List;

/**

* 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!

*/

public interface UserMapper {

int insertUser(UserModel model);

int updateUser(UserModel model);

int deleteUser(Long userId);

List getUserList();

}

UserMapper接口中定义了4个方法,方法的名称需要和UserMapper.xml具体操作的id值一样,这样调用UserMapper接口中的方法的时候,才会对应的找到UserMapper.xml中具体的操作。

比如调用UserMapper接口中的insertUser方法,mybatis查找的规则是:通过接口完整名称.方法名称去Mapper xml中找到对应的操作。

步骤2:通过SqlSession获取Mapper接口对象

SqlSession中有个getMapper方法,可以传入接口的类型,获取具体的Mapper接口对象,如下:

/**

* Retrieves a mapper.

* @param  the mapper type

* @param type Mapper interface class

* @return a mapper bound to this SqlSession

*/

 T getMapper(Class type);

如获取UserMapper接口对象:

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

步骤3:调用Mapper接口的方法对db进行操作

如调用UserMapper接口的insert操作:

@Test

public void insertUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

//创建UserModel对象

UserModel userModel = UserModel.builder().id(System.currentTimeMillis()).name(“路人甲Java”).age(30).salary(50000D).sex(1).build();

//执行插入操作

int insert = mapper.insertUser(userModel);

log.info(“影响行数:{}”, insert);

}

}

案例:使用Mapper接口来实现增删改查

chat02/src/test/java中创建一个测试类,代码如下:

package com.javacode2018.chat02;

import lombok.extern.slf4j.Slf4j;

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.IOException;

import java.io.InputStream;

import java.util.List;

/**

* 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!

*/

@Slf4j

public class UserMapperTest {

private SqlSessionFactory sqlSessionFactory;

@Before

public void before() throws IOException {

//指定mybatis全局配置文件

String resource = “mybatis-config.xml”;

//读取全局配置文件

InputStream inputStream = Resources.getResourceAsStream(resource);

//构建SqlSessionFactory对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

this.sqlSessionFactory = sqlSessionFactory;

}

@Test

public void insertUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

//创建UserModel对象

UserModel userModel = UserModel.builder().id(System.currentTimeMillis()).name(“路人甲Java”).age(30).salary(50000D).sex(1).build();

//执行插入操作

int insert = mapper.insertUser(userModel);

log.info(“影响行数:{}”, insert);

}

}

@Test

public void updateUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

//创建UserModel对象

UserModel userModel = UserModel.builder().id(1L).name(“路人甲Java,你好”).age(18).salary(5000D).sex(0).build();

//执行更新操作

int result = mapper.updateUser(userModel);

log.info(“影响行数:{}”, result);

}

}

@Test

public void deleteUser() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

//定义需要删除的用户id

Long userId = 1L;

//执行删除操作

int result = mapper.deleteUser(userId);

log.info(“影响行数:{}”, result);

}

}

@Test

public void getUserList() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

//执行查询操作

List userModelList = mapper.getUserList();

userModelList.forEach(item -> {

log.info(“{}”, item);

});

}

}

}

大家认真看一下上面的代码,这次我们使用了UserMapper来间接调用UserMapper.xml中对应的操作,可以去运行一下感受一下效果。

Mapper接口使用时注意的几点
  1. Mapper接口的完整类名必须和对应的Mapper xml中的namespace的值一致

  2. Mapper接口中方法的名称需要和Mapper xml中具体操作的id值一致

  3. Mapper接口中方法的参数、返回值可以不和Mapper xml中的一致

Mapper接口的原理

这个使用java中的动态代理实现的,mybatis启动的时候会加载全局配置文件mybatis-config.xml,然后解析这个文件中的mapper元素指定的UserMapper.xml,会根据UserMapper.xml的namespace的值创建这个接口的一个动态代理,具体可以去看一下mybatis的源码,主要使用java中的Proxy实现的,使用java.lang.reflect.Proxy类中的newProxyInstance方法,我们可以创建任意一个接口的一个代理对象:

public static Object newProxyInstance(ClassLoader loader,

Class<?>[] interfaces,

InvocationHandler h)

我们使用Proxy来模仿Mapper接口的实现:

package com.javacode2018.chat02;

import lombok.extern.slf4j.Slf4j;

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.IOException;

import java.io.InputStream;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.List;

/**

* 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!

*/

@Slf4j

public class ProxyTest {

public static class UserMapperProxy implements InvocationHandler {

private SqlSession sqlSession;

private Class<?> mapperClass;

public UserMapperProxy(SqlSession sqlSession, Class<?> mapperClass) {

this.sqlSession = sqlSession;

this.mapperClass = mapperClass;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

log.debug(“invoke start”);

String statement = mapperClass.getName() + “.” + method.getName();

List result = sqlSession.selectList(statement);

log.debug(“invoke end”);

return result;

}

}

private SqlSessionFactory sqlSessionFactory;

@Before

public void before() throws IOException {

//指定mybatis全局配置文件

String resource = “mybatis-config.xml”;

//读取全局配置文件

InputStream inputStream = Resources.getResourceAsStream(resource);

//构建SqlSessionFactory对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

this.sqlSessionFactory = sqlSessionFactory;

}

@Test

public void test1() {

try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true)😉 {

UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[]{UserMapper.class}, new UserMapperProxy(sqlSession, UserMapper.class));

log.info(“{}”, userMapper.getUserList());

}

}

}

上面代码中:UserMapper是没有实现类的,可以通过Proxy.newProxyInstance给UserMapper接口创建一个代理对象,当调用UserMapper接口的方法的时候,会调用到UserMapperProxy对象的invoke方法。

运行一下test1用例,输出如下:

16:34.288 [main] DEBUG com.javacode2018.chat02.ProxyTest - invoke start

16:34.555 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==>  Preparing: SELECT * FROM t_user

16:34.580 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==> Parameters:

16:34.597 [main] DEBUG c.j.chat02.UserMapper.getUserList - <==      Total: 4

16:34.597 [main] DEBUG com.javacode2018.chat02.ProxyTest - invoke end

16:34.597 [main] INFO  com.javacode2018.chat02.ProxyTest - [UserModel(id=2, name=javacode2018, age=30, salary=50000.0, sex=1), UserModel(id=1575621274235, name=路人甲Java, age=30, salary=50000.0, sex=1), UserModel(id=1575621329823, name=路人甲Java, age=30, salary=50000.0, sex=1), UserModel(id=1575623283897, name=路人甲Java, age=30, salary=50000.0, sex=1)]

注意上面输出的invoke startinvoke end,可以看到我们调用userMapper.getUserList时候,被UserMapperProxy#invoke方法处理了。

Mybatis中创建Mapper接口代理对象使用的是下面这个类,大家可以去研究一下:

public class MapperProxyFactory {

private final Class mapperInterface;

private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

public MapperProxyFactory(Class mapperInterface) {

this.mapperInterface = mapperInterface;

}

public Class getMapperInterface() {

return mapperInterface;

}

public Map<Method, MapperMethod> getMethodCache() {

return methodCache;

}

@SuppressWarnings(“unchecked”)

protected T newInstance(MapperProxy mapperProxy) {

return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);

}

public T newInstance(SqlSession sqlSession) {

final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);

return newInstance(mapperProxy);

}

}

案例代码获取方式

扫码添加微信备注:mybatis案例,即可获取

MyBatis系列

  1. MyBatis系列第1篇:MyBatis未出世之前我们那些痛苦的经历

  2. MyBatis系列第2篇:入门篇,带你感受一下mybatis独特的魅力!

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

在清楚了各个大厂的面试重点之后,就能很好的提高你刷题以及面试准备的效率,接下来小编也为大家准备了最新的互联网大厂资料。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
ssLoader(), new Class[] { mapperInterface }, mapperProxy);

}

public T newInstance(SqlSession sqlSession) {

final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);

return newInstance(mapperProxy);

}

}

案例代码获取方式

扫码添加微信备注:mybatis案例,即可获取

MyBatis系列

  1. MyBatis系列第1篇:MyBatis未出世之前我们那些痛苦的经历

  2. MyBatis系列第2篇:入门篇,带你感受一下mybatis独特的魅力!

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-v3EJORMY-1713500857066)]

[外链图片转存中…(img-fUuYSg8D-1713500857069)]

[外链图片转存中…(img-2P933s0w-1713500857070)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

在清楚了各个大厂的面试重点之后,就能很好的提高你刷题以及面试准备的效率,接下来小编也为大家准备了最新的互联网大厂资料。

[外链图片转存中…(img-xuPSbMDO-1713500857073)]

[外链图片转存中…(img-x7T39vhi-1713500857075)]

[外链图片转存中…(img-mZIss9DI-1713500857076)]

[外链图片转存中…(img-SCAbiJv3-1713500857078)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值