Mybatis源码分析三-数据源模块分析,工厂模式的使用

@Override

public void play() {

System.out.println(“超级玛丽游戏开始”);

}

public SuperMarioGame(String name) {

this.name = name;

}

public SuperMarioGame(String begin, String stop, String play) {

this.begin = begin;

this.stop = stop;

this.play = play;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getBegin() {

return begin;

}

public void setBegin(String begin) {

this.begin = begin;

}

public String getStop() {

return stop;

}

public void setStop(String stop) {

this.stop = stop;

}

public String getPlay() {

return play;

}

public void setPlay(String play) {

this.play = play;

}

}

3、定义产品实体类CastlevaniaGame.java

public class CastlevaniaGame implements Game{

private String name;

private String begin;

private String stop;

private String play;

@Override

public void play() {

System.out.println(“恶魔城游戏开始”);

}

public CastlevaniaGame(String name) {

this.name = name;

}

public CastlevaniaGame(String begin, String stop, String play) {

this.begin = begin;

this.stop = stop;

this.play = play;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getBegin() {

return begin;

}

public void setBegin(String begin) {

this.begin = begin;

}

public String getStop() {

return stop;

}

public void setStop(String stop) {

this.stop = stop;

}

public String getPlay() {

return play;

}

public void setPlay(String play) {

this.play = play;

}

}

4、定义开发游戏工厂接口 GameFactory .java

/**

  • 开发游戏工厂类

  • @author DarkKing

*/

public interface GameFactory {

public Game createGame(String gameName);

}

5、定义开发游戏工厂实现类 GameFactoryImpl .java

/**

  • 开发游戏工厂类

  • @author DarkKing

*/

@Component

public class GameFactoryImpl implements GameFactory{

@Override

public Game createGame(String gameName) {

Game game= null;

if(gameName.equals(“superMario”)){

game = new CangSmallMovie(“超级玛丽”);

}else if(gameName.equals(“Castlevania”)){

game= new JiaSmallMovie(“恶魔城”);

}

//开发游戏过程

//…………

//此处省略一万字

return game;

}

}

三、工厂模式

=======

1、工厂模式介绍


工厂模式属于创建型模式,它提供了一种创建对象的最佳方式。定义一个创建对象的接口, 让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。类图如下:

  • 产品接口(Product):产品接口用于定义产品类的功能,具体工厂类产生的所有产品都 必须实现这个接口。调用者与产品接口直接交互,这是调用者最关心的接口;

  • 具体产品类(ConcreteProduct):实现产品接口的实现类,具体产品类中定义了具体的 业务逻辑;

  • 工厂接口(Factory):工厂接口是工厂方法模式的核心接口,调用者会直接和工厂接口 交互用于获取具体的产品实现类;

  • 具体工厂类(ConcreteFactory):是工厂接口的实现类,用于实例化产品对象,不同的具 体工厂类会根据需求实例化不同的产品实现类;

2、为什么要使用工厂模式?


答:对象可以通过 new 关键字、反射、clone 等方式创建,也可以通过工厂模式创建。对于 复杂对象,使用 new 关键字、反射、clone 等方式创建存在如下缺点:

  • 对象创建和对象使用的职责耦合在一起,违反单一原则;

  • 当业务扩展时,必须修改代业务代码,违反了开闭原则; 而使用工厂模式将对象的创建和使用进行解耦,并屏蔽了创建对象可能的复杂过程,相对简 单工厂模式,又具备更好的扩展性和可维护性,优点具体如下:

  • 把对象的创建和使用的过程分开,对象创建和对象使用使用的职责解耦;

  • 如果创建对象的过程很复杂,创建过程统一到工厂里管理,既减少了重复代码,也方便 以后对创建过程的修改维护;

  • 当业务扩展时,只需要增加工厂子类,符合开闭原则;

3、代码示例


1、定义GameFactory抽象工厂类

public interface GameFactory {

public Game createGame();

}

2、CastlevaniaGameFactory产品工厂类

@Component

public class CastlevaniaGameFactory implements GameFactory {

@Override

public Game createGame(String GameName) {

Game game = new CastlevaniaGame(“恶魔城”);

//游戏开发

//…………

//此处省略一万字

return game;

}

}

3、SuperMarioGameFactory 产品工厂类

@Component

public class SuperMarioGameFactory implements GameFactory {

@Override

public Game createGame() {

Game game = new SuperMarioGame(“超级玛丽”);

//游戏开发

//…………

//此处省略一万字

return game;

}

}

了解完工厂模式,我们开始学习数据库的连接池技术的实现原理

四、数据库连接池技术解析

=============

1、数据库连接池技术介绍


数据库连接池技术是提升数据库访问效率常用的手段,使用连接池可以提高连接资源的复用 性,避免频繁创建、关闭连接资源带来的开销,池化技术也是大厂高频面试题。MyBatis 内 部就带了一个连接池的实现,接下来重点解析连接池技术的数据结构和算法;先重点分析下 跟连接池相关的关键类:

  • PooledDataSource:一个简单,同步的、线程安全的数据库连接池

  • PooledConnection:使用动态代理封装了真正的数据库连接对象,在连接使用之前和关 闭时进行增强;

  • PoolState:用于管理 PooledConnection 对象状态的组件,通过两个 list 分别管理空闲状 态的连接资源和活跃状态的连接资源,如下图,需要注意的是这两个 List 使用 ArrayList实现,存在并发安全的问题,因此在使用时,注意加上同步控制;

2、获取资源和回收资源的流程


具体流程参考mybatis源码org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(String, String)

//从连接池获取资源

private PooledConnection popConnection(String username, String password) throws SQLException {

boolean countedWait = false;

PooledConnection conn = null;

long t = System.currentTimeMillis();//记录尝试获取连接的起始时间戳

int localBadConnectionCount = 0;//初始化获取到无效连接的次数

while (conn == null) {

synchronized (state) {//获取连接必须是同步的

if (!state.idleConnections.isEmpty()) {//检测是否有空闲连接

// Pool has available connection

//有空闲连接直接使用

conn = state.idleConnections.remove(0);

if (log.isDebugEnabled()) {

log.debug(“Checked out connection " + conn.getRealHashCode() + " from pool.”);

}

} else {// 没有空闲连接

if (state.activeConnections.size() < poolMaximumActiveConnections) {//判断活跃连接池中的数量是否大于最大连接数

// 没有则可创建新的连接

conn = new PooledConnection(dataSource.getConnection(), this);

if (log.isDebugEnabled()) {

log.debug("Created connection " + conn.getRealHashCode() + “.”);

}

} else {// 如果已经等于最大连接数,则不能创建新连接

//获取最早创建的连接

PooledConnection oldestActiveConnection = state.activeConnections.get(0);

long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();

if (longestCheckoutTime > poolMaximumCheckoutTime) {//检测是否已经以及超过最长使用时间

// 如果超时,对超时连接的信息进行统计

state.claimedOverdueConnectionCount++;//超时连接次数+1

state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;//累计超时时间增加

state.accumulatedCheckoutTime += longestCheckoutTime;//累计的使用连接的时间增加

state.activeConnections.remove(oldestActiveConnection);//从活跃队列中删除

if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {//如果超时连接未提交,则手动回滚

try {

oldestActiveConnection.getRealConnection().rollback();

} catch (SQLException e) {//发生异常仅仅记录日志

/*

Just log a message for debug and continue to execute the following

statement like nothing happend.

Wrap the bad connection with a new PooledConnection, this will help

to not intterupt current executing thread and give current thread a

chance to join the next competion for another valid/good database

connection. At the end of this loop, bad {@link @conn} will be set as null.

*/

log.debug(“Bad connection. Could not roll back”);

}

}

//在连接池中创建新的连接,注意对于数据库来说,并没有创建新连接;

conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);

conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());

conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());

//让老连接失效

oldestActiveConnection.invalidate();

if (log.isDebugEnabled()) {

log.debug("Claimed overdue connection " + conn.getRealHashCode() + “.”);

}

} else {

// 无空闲连接,最早创建的连接没有失效,无法创建新连接,只能阻塞

try {

总结

总的来说,面试是有套路的,一面基础,二面架构,三面个人。

最后,小编这里收集整理了一些资料,其中包括面试题(含答案)、书籍、视频等。希望也能帮助想进大厂的朋友

三面蚂蚁金服成功拿到offer后,他说他累了

三面蚂蚁金服成功拿到offer后,他说他累了

= new PooledConnection(oldestActiveConnection.getRealConnection(), this);

conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());

conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());

//让老连接失效

oldestActiveConnection.invalidate();

if (log.isDebugEnabled()) {

log.debug("Claimed overdue connection " + conn.getRealHashCode() + “.”);

}

} else {

// 无空闲连接,最早创建的连接没有失效,无法创建新连接,只能阻塞

try {

总结

总的来说,面试是有套路的,一面基础,二面架构,三面个人。

最后,小编这里收集整理了一些资料,其中包括面试题(含答案)、书籍、视频等。希望也能帮助想进大厂的朋友

[外链图片转存中…(img-WPFl8DJn-1714421090864)]

[外链图片转存中…(img-nzIaxxAT-1714421090864)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值