【文章内容输出来源:拉勾教育Java高薪训练营】 --- 所有脑图均本人制作,未经允许请勿滥用 ---
〇、 脑图总览
图片可能存在更新延迟,最新脑图会在“传送门”中实时更新。
模块一 脑图传送门
一、 从持久层开始
:) Hello Mybatis
1.1 持久层定义
From360百科:
系统逻辑层面上,专注于实现数据持久化的一个相对独立的领域(Domain),把数据保存到可掉电式存储设备中。持久层是负责向(或者从)一个或者多个数据存储器中存储(或者获取)数据的一组类和组件
1.2 早期JDBC
JDBC虽然是最接近数据库的访问方式,但也是最“僵硬”的,随着项目庞大起来,响应的维护量巨大。
它的问题非常明显:
数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能
Sql语句在代码中硬编码,造成代码不易维护
使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护
对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据 库记录封装成pojo对象解析比较方便
public static void main() {
Connection connection = null; // 准备连接实体
PreparedStatement preparedStatement = null; // 准备statement
ResultSet resultSet = null; // 准备结果集
try {
/* 1. 加载数据库驱动 (适用Mysql5+,8+请使用新驱动com.mysql.cj.jdbc.Driver)*/
Class.forName("com.mysql.jdbc.Driver");
/* 2. 通过驱动管理类获取数据库链接 */
connection = DriverManager
.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
/* 3. 定义sql语句 ? 占位符 */
String sql = "SELECT * FROM user WHERE user_name = ?";
/* 4. 获取预处理statement */
preparedStatement = connection.prepareStatement(sql);
/* 5. 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值 */
preparedStatement.setString(1, "Archie");
/* 6. 向数据库发出sql查询,并接收结果集 */
resultSet = preparedStatement.executeQuery();
/* 7. 遍历查询结果集 */
while (resultSet.next()) {
// Do something ...
}
} catch (Exception e) {
e.printStackTrace();
} finally {
/* 8. 释放资源 */
try {
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
于是一个个持久层框架——Hibernate
、MyBatis
、Spring Data
……横空出世
1.3 自定义持久层框架(借鉴Mybatis)
1.3.1 我们对于JDBC的问题,可以有以下解决思路:
使用数据库连接池 初始化 资源;
将“僵硬的”sql语句抽取到xml配置文件中;
使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射
1.3.2 框架设计
传送门
具体实现代码
有心者可以使用这份代码认真研读,这对后期“手撕”Mybatis源码很有帮助!
二、 Mybatis由浅入深 (代码附小节末 )
2.1 Mybatis基本概念
2.1.1 ORM(Object/Relation Mapping)--对象/关系数据库映射:
编程人员只需利用面向对象的编程语言,把对持久化对象的CRUD操作,转化为对数据库底层的操作。
2.1.2 Mybatis简介与历史:
原是apache的一个开源项目iBatis , 2010年6月这个项目由apache software foundation 迁移到了google code,随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis ,代码于2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
2.1.3 Mybatis优势:
核心SQL可以由程序员自己定制以及优化,且SQL和java编码分离,使得功能边界清晰———前者专注数据、后者专注业务逻辑
2.2 踏出第一步
首先要明确,无论是何种技术,我们最好的学习文档就是 官方网址
-->
Mybatis官网
-----鉴于大部分人在工作中经常使用Mybatis,基本的使用在此简要带过,详细步骤可以参考各大教程博客 ------
2.2.1 开发顺序
确认核心文件SqlMapConfig.xml
pom.xml中添加mybatis依赖
确认数据库的目标table
确认与之对应的POJO类(属性和表对应)
编写“桥梁”——XXMapper.xml
自测
Mybatis的代理开发方式:程序员只编写Mapper接口(相当于Dao接口),由Mybatis识别这些接口并创建动态代理对象。
2.2.2 编写Mapper接口的基本规范:
Mapper.xml文件中的namespace
与mapper接口的全限定名
相同
Mapper接口方法名
和Mapper.xml中定义的每个statement的id
相同
Mapper接口方法的输入参数类型
和mapper.xml中定义的每个sql的parameterType
的类型相同
Mapper接口方法的输出参数类型
和mapper.xml中定义的每个sql的resultType
的类型相同
2.3 核心配置文件sqlMapConfig.xml
官方说明
2.3.1 基本配置
2.3.2 mybatis支持的三种数据源(DataSource)
UNPOOLED :每次被请求时打开和关闭连接
POOLED :这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来
JDNI :为了能在如 EJB 或应用服务器这类容器中使用而实现的数据源
2.3.3 mybatis自生产常用类型别名(TypeAlias)
| 别名 | 数据类型 |
| ------- | -------- |
| string | String |
| long | Long |
| int | Integer |
| _int | int |
| double | Double |
| boolean | Boolean |
2.3.4 动态SQL
| 标签元素 | 作用 | 备注 |
| ------------------------------------------------------------ | -------------------------------------- | ---------- |
| if | 对输入参数进行判定,实现按条件拼接语句 | 单条件分支 |
| choose / when / otherwise | 相当于JAVA中的 if...else...
| 多条件分支 |
| trim | 辅助(前置/后置)拼接 | 处理 SQL 拼接问题 |
| where | 内嵌sql职能处理至'where'后拼接 | 1.若输出是以and开头,会把首个'and'忽略掉 2.内部条件可以全空 |
| set | 和where类似 | 内部条件不可
全空 |
| foreach | 在sql中迭代一个集合 | collection情况: 1. List -> "list" 2. Array -> "array" 3. Map -> 对应key |
| script | 注解中使用动态sql | |
| bind | 在OGNL表达式外创建一个变量并绑定到当前上下文 | |
2.4 复杂映射开发(基于配置)
2.4.1 一对一查询
业务描述:每一个订单包含唯一一个用户信息
分析语句:SELECT * FROM orders o, user u WHERE o.uid = u.id;
2.4.1.1 orders表 + user表
2.4.1.2 Order实体 + User实体
public class User {
private Integer id;
private String userName;
private Integer age;
// ...省略 get/set/toString
}
public class Order {
private Integer id;
private Date orderTime;
private Double total;
// 表明该订单属于哪个用户
private User user;
// ......省略 get/set/toString
}
2.4.1.3 OrderMapper.xml + OrderMapper.java
SELECT * FROM orders o, user u WHERE o.uid = u.id;
public interface OrderMapper {
List listAll();
}
2.4.1.4 自测 & 结果
@Test
public void testDemo() {
SqlSession sqlSession = getFactory().openSession();
List orderList = sqlSession.selectList("orderMapper.listAll");
Assert.assertNotNull(orderList);
for (Order order : orderList) {
System.out.println(order);
}
sqlSession.close();
}
2.4.2 一对多查询
业务描述:一个用户有多个订单,一个订单只从属于一个用户
分析语句:SELECT *,o.id oid FROM user u LEFT JOIN orders o ON u.id=o.uid;
2.4.2.1 修改User实体
public class User {
private Integer id;
private String userName;
private Integer age;
//【新增】表示用户关联的订单
private List orderList;
// ......省略 get/set/toString
}
2.4.2.2 UserMapper.xml + UserMapper.java
SELECT *,o.id oid FROM user u LEFT JOIN orders o ON u.id=o.uid;
public interface UserMapper {
List listAll();
}
2.4.2.3 自测 & 结果
@Test
public void test003() {
SqlSession sqlSession = getFactory().openSession();
List userList = sqlSession.selectList("userMapper.listAllWithOrders");
Assert.assertNotNull(userList);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
2.4.3 多对多查询
业务描述:一个用户有多个角色,一个角色被多个用户使用
语句分析:`SELECT * FROM user u LEFT JOIN sys_user_role ur ON u.id = ur.userid
LEFT JOIN sys_role r ON r.id = ur.roleid`
2.4.3.2 sys_role表 + sys_user_role表
2.4.3.2 创建Role实体 + 修改User实体
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
// ...省略set/get/toString
}
public class User {
private Integer id;
private String userName;
private Integer age;
//表示用户关联的订单
private List orderList;
//【新增】表示用户关联的角色
private List roleList = new ArrayList<>();
// ...省略set/get/toString
}
2.4.3.3 在UserMapper接口中添加方法
public interface UserMapper {
List listAll(); // 获取所有用户(自身)
List listAllWithOrders(); // 获取所有用户和对应的订单信息(一对多)
List listAllWithRole(); // 获取所有用户和他们的角色(多对多)
}
2.4.3.4 修改UserMapper.xml中的配置(多加一个resultMap)
SELECT * FROM user;
SELECT *,o.id oid FROM user u LEFT JOIN orders o ON u.id=o.uid;
SELECT * FROM user u LEFT JOIN sys_user_role ur ON u.id = ur.userid LEFT JOIN sys_role r ON r.id = ur.roleid
2.4.3.5 自测 & 结果
@Test
public void test004() {
SqlSession sqlSession = getFactory().openSession();
List userList = sqlSession.selectList("userMapper.listAllWithRole");
Assert.assertNotNull(userList);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
2.5 复杂映射开发(基于注解)
暂略......
2.6 Mybatis一级缓存
Mybatis的一级缓存默认打开 ,底层的实现是HashMap,生命周期在每一条SqlSession
中
2.6.1 测试 & 结果
@Test
public void test005() {
SqlSession sqlSession = getFactory().openSession();
List userList01 = sqlSession.selectList("userMapper.listAll");
System.out.println(userList01.get(0));
System.out.println("---------------------------------------------------");
List userList02 = sqlSession.selectList("userMapper.listAll");
System.out.println(userList02.get(0));
Assert.assertEquals(userList01, userList02); // 断言:两个对象地址是否一样
}
再试试如果在两次相同操作过程中,执行了其他RUD操作,是否会导致缓存被刷新
@Test
public void test005() {
SqlSession sqlSession = getFactory().openSession();
List userList01 = sqlSession.selectList("userMapper.listAll");
System.out.println(userList01.get(0));
System.out.println("---------------------------------------------------");
User user = new User();
user.setId(1);
user.setUserName("Archie(2.0)");
sqlSession.update("userMapper.updateById", user);
sqlSession.commit();
System.out.println("---------------------------------------------------");
List userList02 = sqlSession.selectList("userMapper.listAll");
System.out.println(userList02.get(0));
Assert.assertEquals(userList01, userList02); // 断言:两个对象地址是否一样
sqlSession.close();
}
2.7 Mybatis二级缓存
Mybatis的二级缓存是跨SqlSession 的,它基于mapper文件中的namespace
——
所以:若两个mapper的namespace相同,就算mapper不同,也共享同一个二级缓存。
2.7.1 打开二级缓存
和一级缓存默认开启不一样,二级缓存需要我们手动开启
还得再UserMapper.xml中开启缓存
...
最后,因为二级缓存的存储介质多种多样(内存/硬盘...),所以我们要将对应POJO类实现Serializable接口
,从而实现序列/反序列化。
public class User implements Serializable
2.7.2 测试 & 结果
A. 二级缓存和sqlSession无关
@Test
public void test006() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
List userList1 = mapper1.listAll();
System.out.println(userList1.get(0));
sqlSession1.close(); // 关闭 1号SqlSession ,清空一级缓存
System.out.println("---------------------------------------------------");
List userList2 = mapper2.listAll();
System.out.println(userList2.get(0));
sqlSession2.close();
Assert.assertNotEquals(userList1, userList2); // 断言:两个对象地址是否不一样
}
B. 执行commit()操作,二级缓存数据清空
@Test
public void test007() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
List userLis1 = mapper1.listAll();
sqlSession1.close(); // 清空一级缓存
System.out.println("-----------------执行commit操作-------------------");
User user = new User();
user.setId(1);
user.setUserName("Archie(3.0)");
mapper2.updateById(user);
sqlSession2.commit();
System.out.println("------------------------------------");
List userList2 = mapper3.listAll();
Assert.assertNotEquals(userLis1, userList2); // 断言:两个对象地址是否不一样
}
2.7.3 二级缓存整合Redis
由于mybatis自带的二级缓存是单服务器工作
,无法在分布式系统上工作,因此需要借助分布式缓存 :【Redis/memcached/ehcache】
2.7.3.1 准备
准备pom依赖
org.mybatis.caches
mybatis-redis
1.0.0-beta2
sqlMapConfig.xml指定分布式缓存类型 + 对应接口是否启用
SELECT * FROM user;
加入redis.properties文件(若无指定修改,可不添加该文件,底层有默认值)
redis.host=localhost
redis.port=6379
redis.connectionTimeout=5000
redis.password=
redis.database=0
测试前 开启Redis服务
Redis快速运行脚本可以自己写:redis-server redis.windows.conf
2.7.3.1 测试
@Test
public void test008() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
List userList1 = mapper1.listAll();
System.out.println(userList1.get(0));
sqlSession1.close(); // 清空一级缓存
System.out.println("---------------------------------------------------");
List userList2 = mapper2.listAll();
System.out.println(userList2.get(0));
sqlSession2.close();
Assert.assertNotEquals(userList1, userList2); // 断言:两个对象地址是否不一样
}
2.8 MyBatis插件(plugin)
暂略...
代码传送门
三、Mybatis源码“斩杀”
攻坚战开始了!O.O
P.S. 之前的自定义持久层框架一定要熟烂于心!
3.1 流程总览
暂略...
3.2 传统方式源码剖析
// 1.使用ClassLoader对文件进行 “流化” !(但还未具体解析)
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 2. 使用XPathParse 解析出 XMLConfigBuilder 对象,调用parse()方法
// -- 2.1. parse()方法内部 利用 XNode 解析出 每个标签并将它们封装在 [JavaBean]Configuration中
// -- 2.2. 构建者模式创建 DefaultSqlSessionFactory 对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 3. 生成DefaultSqlsession实例对象了,并将 Executor 对象封装在其中
// -- 3.1. 其中默认设置了 事务提交方式为:[非自动提交]
sqlSession = sqlSessionFactory.openSession();
// 4. 根据statementid来从Configuration中map集合中获取到了指定的MappedStatement对象
// -- 4.1. 执行 executor.query() 从而 将查询任务委派到了executor执行器
// --- 4.1.2. 顶层query() -> 设置分页值、设置CacheKey
// --- 4.1.2. 判断 执行器是否被关闭、是否需要刷新缓存, 若否 -> 调用queryFromDatabase()方法
// --- 4.1.3. 核心调用SimpleExecutor.doQuery()
// ---- 4.1.3.1. 创建StatementHandler对象
// ---- 4.1.3.2. 构建者模式生成ParameterHandler
// ---- 4.1.3.3. 获取TypeHandler
// ---- 4.1.3.4. 调用ResultSetHandler.handleResultSets() 处理statement
// ***** 底层JDBC操作 *****
// 5. 返回List 的结果
List userList = sqlSession.selectList("com.archie.dao.UserMapper.listAll");
// 6. 释放资源
sqlSession.close();
3.3 Mapper代理方式源码剖析
获取sqlSession前的步骤和 传统方式一致;
// ......
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 通过mapperRegistry 调用 getMapper()方法
// -- 4.1. 从mapperRegistry中的 HashMap 拿 MapperProxyFactory
// -- 4.2. 通过动态代理工厂 生成实例
// --- 4.2.1. 实例的生成过程中实现了对每一个SqlSession 的动态代理
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 获取到 代理对象后,就可以直接调用被代理接口的方法了
// -- 5.1. 代理对象,调用方法时都是执行MapperPorxy中的invoke()方法
// ---- 5.1.1. invoke()中,若非Object的方法,则获取MapperMethod对象,【重点】它来最终调用execute()方法
// ---- 5.1.2. execute()中,判断方法类型-->CRUD, 最终交由ResultHandler处理,返回Object型的result值
List userList01 = mapper.listAll();
3.4 二级缓存源码剖析
查询请求优先级:【 二级缓存 > 一级缓存 > 数据库 】
二级缓存和具体namespace绑定,一个Mapper中有一个Cache,相同Mapper的MapperStatement共用一个Cache
3.4.1 思考A - ‘为什么说一个Mapper中的Cache被共用?’
在3.2小节中,我们分析步骤2时,sqlMapConfig.xml 的具体解析是由XMLConfigBuilder调用parse()解析 的,它中途需要解析到
标签,这个标签也是我们打开二级缓存的标志。所以我们得分析从这里开始。
高清传送门
3.4.2 思考B - ‘为什么优先级 :二级缓存 > 一级缓存?’
P.S. 二级缓存开启时,走的是CachingExecutor实现类
3.4.3 思考C - ‘为何只有SqlSession提交或者关闭后,二级缓存才会生效?’
暂略...
3.5 延迟加载源码剖析
暂略...
3.5.1 使用场景
当需要用到数据的时候才进行多表关联查询。
建议使用场景:
懒加载是基于 嵌套查询的!
3.5.2 实现
3.5.2.1 UserMapper.xml + UserMapper.java
指明当前 collection标签 需要定位的内嵌sql select="com.archie.dao.OrderMapper.listByUid"
传给内嵌sql的参数 column="id"
实现局部懒加载 fetchType="lazy"
SELECT * FROM user WHERE id = #{id};
User listById(User user);
3.5.2.2 OrderMapper.xml + OrderMapper.java
SELECT * FROM orders WHERE uid = #{uid};
List listByUid(Integer uid);
3.5.2.3 自测 & 结果
@Test
public void test009() {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(1);
User resultUser = sqlSession.selectOne("com.archie.dao.UserMapper.listById", user);
System.out.println(resultUser.getUserName());
System.out.println("****** 还未使用到订单信息 *******");
System.out.println("********** 现在想要获取对应用户的订单信息了 ************");
System.out.println(resultUser.getOrderList());
}
3.5.2.4 全局配置懒加载
在sqlMapConfig.xml中加入
即可实现全局懒加载
懒加载的优先级: 局部 高于 全局
因此——当全局开启时,若有部分接口不想懒加载,可以直接 fetchType="eager"
实现局部立即加载
3.5.3 源码剖析
暂略...
四、 设计模式
4.1 Builder构建者模式
4.1.1 通俗定义
使用多个简单对象 --构建--> 复杂对象 的过程。
4.1.2 简单实现
Demo【构建一个Computer复杂对象】
【step-A】 定义目标对象Computer
public class Computer {
/* 显示器部件 */
private String disPlayer;
/* 主机部件 */
private String mainEngine;
/* 鼠标部件 */
private String mouse;
/* 键盘部件 */
private String keyBoard;
// ...省略 set、get、toString
}
【step-B】 定义构建者ComputerBuilder
public class ComputerBuilder {
/* 定义目标对象 */
private Computer target = new Computer();
/**
* 安装显示器部件给目标对象
* @param disPlayer
*/
public void installDisPlayer(String disPlayer) {
target.setDisPlayer(disPlayer);
}
/**
* 安装主机部件给目标对象
* @param mainEngine
*/
public void installMainEngine(String mainEngine) {
target.setMainEngine(mainEngine);
}
/**
* 安装鼠标部件给目标对象
* @param mouse
*/
public void installMouse(String mouse) {
target.setMouse(mouse);
}
/**
* 安装键盘部件给目标对象
* @param keyBoard
*/
public void installKeyBoard(String keyBoard) {
target.setKeyBoard(keyBoard);
}
/**
* 实现复杂对象构建
* @return
*/
public Computer build() {
return target;
}
}
测试
public class realizeBuildingComputer {
public static void main(String[] args) {
ComputerBuilder builder = new ComputerBuilder();
builder.installDisPlayer("A-1001-显示器");
builder.installMainEngine("B-2344-主机");
builder.installMouse("C-6617-鼠标");
builder.installKeyBoard("D-4990-键盘");
/* 安装部件完毕,生产电脑 */
Computer computer = builder.build();
/* 测试打印 */
System.out.println("computer = \n" + computer);
}
}
4.1.3 mybatis中的体现
高清传送门
4.2 工厂模式
(目前只需掌握 /简单工厂模式/ 即可)
4.2.1 通俗定义
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于创建型模式。
专门有一个类 ——> 根据参数的不同返回不同类的实例 (这些实例往往是同一个父类)
4.2.2 简单实现
Demo 【一个厂商生产不同品牌的电脑】
【Step-A】创建产品抽象类
public abstract class Computer {
/* 启动电脑方式 :由具体产品实现 */
public abstract void start();
}
【Step-B】创建具体产品
创建不同品牌的电脑,都继承抽象父类->Computer
public class HPComputer extends Computer{
@Override
public void start() {
System.out.println("惠普电脑启动");
}
}
public class LenovoComputer extends Computer {
@Override
public void start() {
System.out.println("联想电脑开机");
}
}
【Step-C】创建工厂类
提供静态方法createComputer用来生产电脑(用户只需要传输想要的品牌,响应对象即刻实例化)
public class ComputerFactory {
public static Computer createComputer(String brand) {
Computer computer = null;
switch (brand) {
case "lenovo":
computer = new LenovoComputer();
case "hp":
computer = new HPComputer();
}
return computer;
}
}
测试
public static void main(String[] args) {
ComputerFactory.createComputer("hp").start();
System.out.println("-----------");
ComputerFactory.createComputer("lenovo").start();
}
4.2.3 Mybatis中体现
SqlSessionFactory中的openSession有很多重载,支持各类参数类别的输入,从而构建核心SqlSeesion对象
这个工厂的核心底层方法是openSessionFromDataSource
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 根据参数创建制定类型的Executor
final Executor executor = configuration.newExecutor(tx, execType);
// 执行器注入构建方法,返回SqlSession对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
4.3 代理模式
(目前掌握动态代理 即可)
4.3.1 通俗定义
给某一个对象提供一个代理,并由代理对象控制对原对象的引用
4.3.2 简单实现
Demo【对Person实体进行代理】
【Step-A】‘人’接口和默认实现类
public interface Person {
void doSomething();
}
public class Justin implements Person{
@Override
public void doSomething() {
System.out.println("Justin is doing something...");
}
}
【Step-B】具体的代理实现类
public class JdkDynamicProxyImpl implements InvocationHandler {
// 声明被代理的对象
private Person person;
// 构造函数
public JdkDynamicProxyImpl(Person person) {
this.person = person;
}
/**
* 获取代理对象
* @return
*/
public Object getTarget() {
Object proxyInstance = Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);
return proxyInstance;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("...对原方法进行前置增强");
Object invoke = method.invoke(person, args); // 原方法的执行
System.out.println("...对原方法进行后置增强");
return invoke;
}
}
测试
public class ProxyTest {
public static void main(String[] args) {
System.out.println("【直接调用某人类的方法】");
Justin justin = new Justin();
justin.doSomething();
System.out.println("-----------------");
System.out.println("【使用代理类调用同一个人类的行为】");
Person proxyJustn = (Person) new JdkDynamicProxyImpl(new Justin()).getTarget();
proxyJustn.doSomething();
}
}
4.3.3 Mybatis中体现
代理模式是MyBatis的核心模式
由于这个模式,我们只需要编写XXXMapper.java
接口,而不需要实现;由MyBatis完成具体SQL的执行。
高清传送门
你可能感兴趣的:(拉勾教育学习-笔记分享の"斩杀"框架篇(持久层))
基于深度学习的半导体检测与预测算法研究(二)
埃菲尔铁塔_CV算法
深度学习 人工智能 神经网络 opencv 计算机视觉 python
摘要随着半导体行业的飞速发展,对生产过程中的检测和性能预测提出了更高要求。深度学习凭借其强大的数据处理和特征提取能力,在半导体领域展现出巨大的应用潜力。本文详细探讨了深度学习在半导体缺陷检测、工艺参数预测等方面的应用原理和方法,介绍了常见的深度学习模型如卷积神经网络(CNN)、循环神经网络(RNN)及其变体在半导体数据处理中的应用,分析了模型训练与优化的关键技术,并通过实际案例验证了深度学习算法在
基于深度学习的半导体算法原理及应用
埃菲尔铁塔_CV算法
算法 机器学习 人工智能 计算机视觉 深度学习 python
摘要随着半导体产业的持续发展,深度学习技术在该领域的应用日益广泛且深入。本文全面阐述了基于深度学习的半导体算法原理,涵盖卷积神经网络(CNN)、循环神经网络(RNN)及其变体长短时记忆网络(LSTM)和门控循环单元(GRU)等在半导体制造过程监测、缺陷检测、性能预测等方面的应用。详细分析了这些算法处理半导体相关数据的机制,探讨了算法实现中的关键技术,如数据预处理、模型训练与优化等。通过实际案例展示
计算机视觉国内外研究现状(综述)
埃菲尔铁塔_CV算法
计算机视觉
1.国内外研究进展1.2.1特征提取研究进展特征提取是图像处理的一个重要环节,是进行身份识别和行为识别的重要部分。近年来,针对不同特征的提取,国内外学者提出了许多特征提取算法,同样特征提取的效果大都不错。但是在复杂的猪舍环境中提取猪的特征还是比较困难的。下面针对几种目前常用的特征提取算法进行一些介绍。(1)传统的特征提取算法传统特征提取算法已经发展了很久,现阶段比较成熟,是深度学习算法出来之前研究
一、系统分析师考试介绍
Rainbow酱
系统分析 系统分析 软考
科目1考点考试介绍考试报名、考试科目、大纲及考点分析、证书价值、常见问题。视频课程规划、推荐资料、学习方法。计算机组成与结构数据的表示:进制转换、编码表示、逻辑运算、浮点数。校验码:奇偶校验码、循环冗余校验码、海明校验码。计算机硬件:硬件组成、CPU、寄存器等。计算机指令:寻址方式、指令流水线计算。计算机体系结构:Flynn分类,指令系统CISC和RISC。计算机存储系统:分级存储、cache、存
3dgs 2025 学习笔记
AI算法网奇
3d渲染 学习 笔记
CVPR20243D方向总汇包含(3DGS、三维重建、深度补全、深度估计、全景定位、表面重建和特征匹配等)_cvpr2024-structure-awaresparse-viewx-ray3dreconstr-CSDN博客https://github.com/apple/ml-hugs3DGSCOLMAP-Free3DGaussianSplatting⭐codeprojectFeature3DGS
Datawhale数学建模导论课程第八章学习心得(I)一时间序列与投资模型
星.惜尘
数学建模
学习链接:Datawhale数学建模教程Descriptionhttps://datawhalechina.github.io/intro-mathmodel/#/CH8/%E7%AC%AC8%E7%AB%A0-%E6%97%B6%E9%97%B4%E5%BA%8F%E5%88%97?id=_811-%e6%97%b6%e9%97%b4%e5%ba%8f%e5%88%97%e7%9a%84%e5%
Apache SeaTunnel 社区2025年全年计划公布,共同构建下一代数据集成生态
数据库
ApacheSeaTunnel社区正在全球范围内寻找热爱开源、乐于分享的技术先锋!无论你是开发者、用户、布道者还是行业专家,这里都有属于你的舞台。欢迎社区有志之士加入我们,一起推动开源数据集成工具的创新与发展!ApacheSeaTunnel社区全年活动规划一览:https://gzg9x067ms.feishu.cn/base/Hnp1bIKqLaAaTQsqzKscMJ0OnFd...申请流程:
政企学习考试系统(源码+文档+部署+讲解)
开源项目介绍
引言在数字化时代背景下,政企学习考试系统为企业和政府机构提供了一个高效的学习和培训环境。通过整合多种教育资源和学习工具,该平台旨在提升员工的专业技能和知识水平,促进组织的持续发展和创新。系统概述政企学习考试系统采用前后端分离的架构设计,服务端基于MySQL5.7+、JDK1.8+和Redis,前端则采用VUE2.6.14和element-ui2.15.6,并在NODE14.21.3(>=8.9)环
当今前沿技术大解密
火龙果wa
经验分享
虚拟现实技术在教育领域可有大作用啦!它能带来沉浸式学习,让学生仿佛身临其境。这样学生就会更投入,学习效果自然就好啦。比如说,在一些科学课程中,学生可以通过VR体验太空漫步,直观感受宇宙的奥秘。还有在历史课上,能“穿越”回古代,亲眼见证历史事件。像有个学校用VR教地理,学生们对地理知识的理解和记忆明显增强了。这种创新应用真的很棒,让学习变得有趣又高效。以后肯定会有更多学校用上VR技术,让教育变得更精
LLM大模型产品经理学习指南【2025全新版】:极致详细,一篇搞定!
大模型入门学习
产品经理 语言模型 人工智能 DeepSeek 大模型 学习 LLM
前言·随着人工智能技术的蓬勃发展,尤其是大模型(LargeModel)的强势兴起,越来越多的企业对这一领域愈发重视并加大投入。作为大模型产品经理,需具备一系列跨学科的知识与技能,方能有效地推动产品的开发、优化以及市场化进程。以下是一份详尽的大模型产品经理学习路线,旨在助力你构建所需的知识体系,实现从零基础到精通的蜕变。一、基础知识阶段(一)计算机科学基础数据结构与算法:深入理解基本的数据结构(如数
2024年前端最全Java进阶(五十五)-Java Lambda表达式入门_eclipse lambda(2),程序员面试技巧和注意事项
2401_84435192
程序员 前端 面试 学习
算法冒泡排序选择排序快速排序二叉树查找:最大值、最小值、固定值二叉树遍历二叉树的最大深度给予链表中的任一节点,把它删除掉链表倒叙如何判断一个单链表有环由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】"And
2024年Java进阶(五十五)-Java Lambda表达式入门_eclipse lambda,2024年最新阿里员工面试
2401_84446712
程序员 前端 面试 学习
最后一个好的心态和一个坚持的心很重要,很多冲着高薪的人想学习前端,但是能学到最后的没有几个,遇到困难就放弃了,这种人到处都是,就是因为有的东西难,所以他的回报才很大,我们评判一个前端开发者是什么水平,就是他解决问题的能力有多强。开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】分享一些前端面试题以及学习路线给大家###基本的Lambda例子 现在,我们已经知道什么是l
02.单一职责原则详解
java
02.单一职责原则详解目录介绍01.问题思考分析02.单一职责原则介绍03.如何理解单一指责04.用例子理解单一职责05.为何遵守单一原则06.方法层面单一职责07.接口层面单一职责08.类层面单一职责09.单一职责判断模糊10.单一职责判断原则11.最后总结一下12.更多内容推荐推荐一个好玩网站一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网https://yccoding.com/设
前瞻技术:塑造未来生活的新趋势
火龙果wa
生活 人工智能 经验分享
人工智能在艺术创作中的应用越来越普遍。AI可以生成画作、音乐和文学作品。它通过分析大量数据,学习艺术风格,并能创造出独特的作品。AI创作的艺术作品有几个特点。首先,它可以快速完成创作,节省时间。第二,AI能够融合多种风格。这使得作品更加多样化,有了新的表现形式。此外,AI常常会产生一些意想不到的创意,这能激发人们的灵感。艺术家与AI的合作也在逐渐发展。很多艺术家开始尝试与AI共同创作。他们使用AI
python 学习路线
Coding Happily
python 学习 windows
学习顺序《python编程:从入门到实践》《Head-FirstPython》《“笨方法”学python3》《PythonCookbook》《Python机器学习基础教程》《FluentPython》《Python编程》《Python编程:从入门到实践》变量变量命名:仅用小写和下划线。变量本质:指向特定的值。字符串在字符串中使用变量:f’{varies1}{varies2}’更早版本:‘{}{}’
docker 构建 lnmp 环境
dockerlnmp
使用docker-compose编排的一套lnmp环境,并补充了nginx/php/mysql/redis的配置文件,补充了php的常用扩展。给到了fpm/swoole的部署、运行示例。可以方便大家快速搭建开发、生产环境、学习docker技能(涉及了镜像打包、Entrypoint、yml高大上的写法extends&引用)。github完整示例:docker-lnmpdocker-lnmp.envC
03.开闭原则详细介绍
android
03.开闭原则详细介绍目录介绍01.问题思考的分析02.如何理解开闭原则03.开闭原则的背景04.开闭原则比较难学05.实现开闭原则方式06.画图形案例分析07.银行业务案例分析08.开闭原则优缺点09.开闭原则的总结推荐一个好玩网站一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网https://yccoding.com/设计模式Git项目地址:https://github.com/ya
软件供应链风险检测与治理:研发团队如何应对复杂的安全挑战
安全测试
此分享来自于悬镜安全技术合伙人周幸在FCIS2024网络安全创新大会的实战攻防与供应链安全高峰论坛上的分享。01「软件供应链安全」背景首先我们要明确什么是软件供应链和软件供应链安全。大家在各种各样的场合其实都看到过一些类似的定义。软件供应链安全是指软件设计与开发的各个阶段,来自本身的编码过程、工具、设备或供应链上游的代码、模块和服务的安全,以及软件交付渠道和使用安全的总和。在软件供应链维度,我们可
DBA | Oracle 数据库体系结构简述!
全栈工程师修炼指南
企业IT运维实践 数据库 dba oracle
[知识是人生的灯塔,只有不断学习,才能照亮前行的道路]前言简述描述:为了对得起作者UP主公众号【全栈工程师修炼指南】中的【全栈】二字,从今天开始作者选择一门自己工作中常常使用的到的以及全球最流行的关系型数据库Oracle来进行学习,并记录学习过程,以供后续的自己复习回顾和帮助各位看友快速上手,从入门到高新,请各位看友一定要关注、订阅【#Oracle学习之路】专栏。上一章,我们简单介绍了ORACLE
斗罗大陆史莱克学院通用礼包兑换码分享 最新兑换码大全2024
荣华富贵8
程序员的知识储备 经验分享
斗罗大陆史莱克学院对话那么怎么获得?官方经常会发放游戏礼包码,想要得到最新的礼包兑换码,那么大家可以来小编这里领取,小编会把最新的通用礼包码都分享在下方,大家赶紧来小编这里领取礼包码吧。斗罗大陆史莱克学院兑换码大全一、通用兑换码1、vip6662、vip8883、vip9994、svip6665、svip8886、svip9997、dalao6668、dalao8889、dalao999二、全新兑
联想Y7000P win11笔记本双硬盘安装Ubuntu20双系统和显卡驱动
自动驾驶仿真测试
ubuntu linux NVIDIA 双系统
最新需要一个Ubuntu系统进行学习和工作,于是在笔记本上安装双系统。电脑为联想Y7000P,win11系统,电脑自带一块固态硬盘,我又加装了一块。所以win11在一块硬盘上,Ubuntu20准备安装在另一块硬盘上。参考了这位博主的步骤,但是不完全相同,感谢博主。安装U盘准备(1)镜像下载官网提供了最新版本目前为22.04的下载链接。由于我需要20.04,于是去了官网这里下载。还提供了国内的一些镜
联想Y7000 2024版本笔记本 RTX4060安装ubuntu22.04双系统及深度学习环境配置
七七@你一起学习
深度学习 python
目录1..制作启动盘2.Windows磁盘分区,删除原来ubuntu的启动项3.四个设置4.安装ubuntu5.ubuntu系统配置1..制作启动盘先下载镜像文件,注意版本对应。Rufus-轻松创建USB启动盘用rufus制作时,需要注意选择正确的分区类型和系统类型。不然安装的系统会有问题!2.Windows磁盘分区,删除原来ubuntu的启动项手把手教你调整电脑磁盘的分区大小_调整分区大小-CS
抖音“碰一碰”发视频:短视频社交的新玩法
云罗张晓_za898668
碰一碰源码 碰碰卡源码 碰一碰发视频 网络 线性代数 php c语言 android 矩阵
随着短视频平台的兴起,用户的创作与分享需求日益增长。而如何让视频分享更加便捷、有趣,则成为各大平台优化的重点方向之一。抖音作为国内领先的短视频平台,在2023年推出了“碰一碰”功能,通过近距离通信技术实现了设备间的快速连接和视频分享。这一功能不仅提升了用户体验,也为短视频社交带来了全新的玩法。本文将深入解析抖音“碰一碰”发视频的技术实现、应用场景以及其对用户行为的影响。---技术解析:抖音“碰一碰
【鸿蒙在OpenHarmony系统上集成OpenCV,实现图片裁剪】
萌虎不虎
OpenHarmony harmonyos opencv 华为
鸿蒙在OpenHarmony系统上集成OpenCV,实现图片裁剪OpenCV介绍OpenCV(OpenSourceComputerVisionLibrary)是一个开源的计算机视觉和机器学习软件库。它由一系列的C函数和少量C++类构成,同时提供Python、Java和MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV具有极广的应用领域,它包括但不限于:人脸识别和物
Win11华硕笔记本打不开edge浏览器怎么办?
xhp618
笔记1 edge 前端
win11是微软新推出的系统,还不是很稳定,很多用户在使用过程中都有遇到一些小问题,如华硕笔记本用户安装win11后打不开edge浏览器了,这该怎么办?下面我们就来看看详细的解决方法。具体步骤如下:1、首先按下快捷键“win+r”进入windows设置界面。编辑2、然后在搜索框中输入“用户账户控制”。编辑3、点击进入之后,将下方的滑块划动至上半部分。编辑4、然后点击“确定”,并重启计算机,打开ed
使用 HuggingFace 库进行本地嵌入向量生成
qq_37836323
python 人工智能 开发语言
在当今的AI和机器学习应用中,嵌入向量(embeddings)已成为不可或缺的一部分。嵌入向量能够将文本等高维数据转换为低维稠密向量,从而便于计算和分析。在本文中,我们将介绍如何使用HuggingFace库在本地生成嵌入向量,并演示相关代码。环境准备首先,我们需要安装一些必要的依赖库。可以通过以下命令进行安装:#安装必要的库!pipinstallsentence-transformers!pipi
arm板部署离线瓦片地图
陌虚友
arm开发
引言:技术使用qt的qml自带Map组件,没必要像网上那样用纯qt编写各种复杂的代码,直接部署一个自己的地图瓦片源,像调库一般,用几行代码就能简单的实现类似高德的离线地图效果,支持旋转、倾斜,缩放各种基本地图操作,本人的arm板为正点原子的stm32mp157,文件系统用的也是正点的出厂文件系统,同时十分推荐想学习mpu的朋友用正点的板子1.准备瓦片地图使用java编写的开源地图下载器下载瓦片地图
使用gRPC代替SpringCloud微服务项目中的RPC框架OpenFeign
Gloic
spring cloud 微服务 rpc java
这是目录哦一.前言二.代码仓库三.关于gRPC和OpenFeign四.使用gRPC替代OpenFeign1.原OpenFeign客户端2.proto接口定义3.gRPC服务端4.gRPC客户端5.服务测试五.总结一.前言前段时间一直在忙着另一门课程的SpringCloud微服务项目,其中各个微服务之间使用的是OpenFeign进行服务之间的接口调用。这时候刚好在网络程序设计的课程中学习到了gRPC
Kivy 模块使用python语言编译android可用的apk——开篇
静候光阴
Kivy编译apk技术全面解析 android python kivy ubntu linux buildozer
本专栏目标,是将使用kivy库编辑的python语言文件,通过编译可以直接在android环境下执行的apk(亲测鸿蒙可用)。学习本专栏前,请学习kivy的基本操作,可以参考我之前的免费专栏内容:《Python+Kivy(App开发)从入门到实践》自学笔记:Python文件+.kv文件实现“Helloworld”_kivykv文件_静候光阴的博客-CSDN博客由于编译过程中依赖安装和配置问题会造成
精通LangChain:如何使用Unstructured处理多种格式的图像文档
hshahtjtbh
langchain python
#引言随着人工智能和深度学习的快速发展,文档图像分析(DocumentImageAnalysis,DIA)在许多领域中变得至关重要。然而,处理多种图像格式的文档仍然是一个挑战。本文将介绍如何使用Unstructured库,通过LangChain框架加载和处理多种格式的图像文档,帮助您在DIA任务中实现更高效的工作流程。#主要内容##安装Unstructured在开始之前,确保安装了Unstruct
apache 安装linux windows
墙头上一根草
apache inux windows
linux安装Apache 有两种方式一种是手动安装通过二进制的文件进行安装,另外一种就是通过yum 安装,此中安装方式,需要物理机联网。以下分别介绍两种的安装方式
通过二进制文件安装Apache需要的软件有apr,apr-util,pcre
1,安装 apr 下载地址:htt
fill_parent、wrap_content和match_parent的区别
Cb123456
match_parent fill_parent
fill_parent、wrap_content和match_parent的区别:
1)fill_parent
设置一个构件的布局为fill_parent将强制性地使构件扩展,以填充布局单元内尽可能多的空间。这跟Windows控件的dockstyle属性大体一致。设置一个顶部布局或控件为fill_parent将强制性让它布满整个屏幕。
2) wrap_conte
网页自适应设计
天子之骄
html css 响应式设计 页面自适应
网页自适应设计
网页对浏览器窗口的自适应支持变得越来越重要了。自适应响应设计更是异常火爆。再加上移动端的崛起,更是如日中天。以前为了适应不同屏幕分布率和浏览器窗口的扩大和缩小,需要设计几套css样式,用js脚本判断窗口大小,选择加载。结构臃肿,加载负担较大。现笔者经过一定时间的学习,有所心得,故分享于此,加强交流,共同进步。同时希望对大家有所
[sql server] 分组取最大最小常用sql
一炮送你回车库
SQL Server
--分组取最大最小常用sql--测试环境if OBJECT_ID('tb') is not null drop table tb;gocreate table tb( col1 int, col2 int, Fcount int)insert into tbselect 11,20,1 union allselect 11,22,1 union allselect 1
ImageIO写图片输出到硬盘
3213213333332132
java image
package awt;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imagei
自己的String动态数组
宝剑锋梅花香
java 动态数组 数组
数组还是好说,学过一两门编程语言的就知道,需要注意的是数组声明时需要把大小给它定下来,比如声明一个字符串类型的数组:String str[]=new String[10]; 但是问题就来了,每次都是大小确定的数组,我需要数组大小不固定随时变化怎么办呢? 动态数组就这样应运而生,龙哥给我们讲的是自己用代码写动态数组,并非用的ArrayList 看看字符
pinyin4j工具类
darkranger
.net
pinyin4j工具类Java工具类 2010-04-24 00:47:00 阅读69 评论0 字号:大中小
引入pinyin4j-2.5.0.jar包:
pinyin4j是一个功能强悍的汉语拼音工具包,主要是从汉语获取各种格式和需求的拼音,功能强悍,下面看看如何使用pinyin4j。
本人以前用AscII编码提取工具,效果不理想,现在用pinyin4j简单实现了一个。功能还不是很完美,
StarUML学习笔记----基本概念
aijuans
UML建模
介绍StarUML的基本概念,这些都是有效运用StarUML?所需要的。包括对模型、视图、图、项目、单元、方法、框架、模型块及其差异以及UML轮廓。
模型、视与图(Model, View and Diagram)
&
Activiti最终总结
avords
Activiti id 工作流
1、流程定义ID:ProcessDefinitionId,当定义一个流程就会产生。
2、流程实例ID:ProcessInstanceId,当开始一个具体的流程时就会产生,也就是不同的流程实例ID可能有相同的流程定义ID。
3、TaskId,每一个userTask都会有一个Id这个是存在于流程实例上的。
4、TaskDefinitionKey和(ActivityImpl activityId
从省市区多重级联想到的,react和jquery的差别
bee1314
jquery UI react
在我们的前端项目里经常会用到级联的select,比如省市区这样。通常这种级联大多是动态的。比如先加载了省,点击省加载市,点击市加载区。然后数据通常ajax返回。如果没有数据则说明到了叶子节点。 针对这种场景,如果我们使用jquery来实现,要考虑很多的问题,数据部分,以及大量的dom操作。比如这个页面上显示了某个区,这时候我切换省,要把市重新初始化数据,然后区域的部分要从页面
Eclipse快捷键大全
bijian1013
java eclipse 快捷键
Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复制当前行到上一行(复制增加)Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)Alt+↑ 当前行和上面一行交互位置(同上)Alt+← 前一个编辑的页面Alt+→ 下一个编辑的页面(当然是针对上面那条来说了)Alt+En
js 笔记 函数
征客丶
JavaScript
一、函数的使用
1.1、定义函数变量
var vName = funcation(params){
}
1.2、函数的调用
函数变量的调用: vName(params);
函数定义时自发调用:(function(params){})(params);
1.3、函数中变量赋值
var a = 'a';
var ff
【Scala四】分析Spark源代码总结的Scala语法二
bit1129
scala
1. Some操作
在下面的代码中,使用了Some操作:if (self.partitioner == Some(partitioner)),那么Some(partitioner)表示什么含义?首先partitioner是方法combineByKey传入的变量,
Some的文档说明:
/** Class `Some[A]` represents existin
java 匿名内部类
BlueSkator
java匿名内部类
组合优先于继承
Java的匿名类,就是提供了一个快捷方便的手段,令继承关系可以方便地变成组合关系
继承只有一个时候才能用,当你要求子类的实例可以替代父类实例的位置时才可以用继承。
在Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。
内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类如同一个人是由大脑、肢体、器官等身体结果组成,而内部类相
盗版win装在MAC有害发热,苹果的东西不值得买,win应该不用
ljy325
游戏 apple windows XP OS
Mac mini 型号: MC270CH-A RMB:5,688
Apple 对windows的产品支持不好,有以下问题:
1.装完了xp,发现机身很热虽然没有运行任何程序!貌似显卡跑游戏发热一样,按照那样的发热量,那部机子损耗很大,使用寿命受到严重的影响!
2.反观安装了Mac os的展示机,发热量很小,运行了1天温度也没有那么高
&nbs
读《研磨设计模式》-代码笔记-生成器模式-Builder
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
/**
* 生成器模式的意图在于将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示(GoF)
* 个人理解:
* 构建一个复杂的对象,对于创建者(Builder)来说,一是要有数据来源(rawData),二是要返回构
JIRA与SVN插件安装
chenyu19891124
SVN jira
JIRA安装好后提交代码并要显示在JIRA上,这得需要用SVN的插件才能看见开发人员提交的代码。
1.下载svn与jira插件安装包,解压后在安装包(atlassian-jira-subversion-plugin-0.10.1)
2.解压出来的包里下的lib文件夹下的jar拷贝到(C:\Program Files\Atlassian\JIRA 4.3.4\atlassian-jira\WEB
常用数学思想方法
comsci
工作
对于搞工程和技术的朋友来讲,在工作中常常遇到一些实际问题,而采用常规的思维方式无法很好的解决这些问题,那么这个时候我们就需要用数学语言和数学工具,而使用数学工具的前提却是用数学思想的方法来描述问题。。下面转帖几种常用的数学思想方法,仅供学习和参考
函数思想
把某一数学问题用函数表示出来,并且利用函数探究这个问题的一般规律。这是最基本、最常用的数学方法
pl/sql集合类型
daizj
oracle 集合 type pl/sql
--集合类型
/*
单行单列的数据,使用标量变量
单行多列数据,使用记录
单列多行数据,使用集合(。。。)
*集合:类似于数组也就是。pl/sql集合类型包括索引表(pl/sql table)、嵌套表(Nested Table)、变长数组(VARRAY)等
*/
/*
--集合方法
&n
[Ofbiz]ofbiz初用
dinguangx
电商 ofbiz
从github下载最新的ofbiz(截止2015-7-13),从源码进行ofbiz的试用
1. 加载测试库
ofbiz内置derby,通过下面的命令初始化测试库
./ant load-demo (与load-seed有一些区别)
2. 启动内置tomcat
./ant start
或
./startofbiz.sh
或
java -jar ofbiz.jar
&
结构体中最后一个元素是长度为0的数组
dcj3sjt126com
c gcc
在Linux源代码中,有很多的结构体最后都定义了一个元素个数为0个的数组,如/usr/include/linux/if_pppox.h中有这样一个结构体: struct pppoe_tag { __u16 tag_type; __u16 tag_len; &n
Linux cp 实现强行覆盖
dcj3sjt126com
linux
发现在Fedora 10 /ubutun 里面用cp -fr src dest,即使加了-f也是不能强行覆盖的,这时怎么回事的呢?一两个文件还好说,就输几个yes吧,但是要是n多文件怎么办,那还不输死人呢?下面提供三种解决办法。 方法一
我们输入alias命令,看看系统给cp起了一个什么别名。
[root@localhost ~]# aliasalias cp=’cp -i’a
Memcached(一)、HelloWorld
frank1234
memcached
一、简介
高性能的架构离不开缓存,分布式缓存中的佼佼者当属memcached,它通过客户端将不同的key hash到不同的memcached服务器中,而获取的时候也到相同的服务器中获取,由于不需要做集群同步,也就省去了集群间同步的开销和延迟,所以它相对于ehcache等缓存来说能更好的支持分布式应用,具有更强的横向伸缩能力。
二、客户端
选择一个memcached客户端,我这里用的是memc
Search in Rotated Sorted Array II
hcx2013
search
Follow up for "Search in Rotated Sorted Array":What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given ta
Spring4新特性——更好的Java泛型操作API
jinnianshilongnian
spring4 generic type
Spring4新特性——泛型限定式依赖注入
Spring4新特性——核心容器的其他改进
Spring4新特性——Web开发的增强
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
Spring4新特性——Groovy Bean定义DSL
Spring4新特性——更好的Java泛型操作API
Spring4新
CentOS安装JDK
liuxingguome
centos
1、行卸载原来的:
[root@localhost opt]# rpm -qa | grep java
tzdata-java-2014g-1.el6.noarch
java-1.7.0-openjdk-1.7.0.65-2.5.1.2.el6_5.x86_64
java-1.6.0-openjdk-1.6.0.0-11.1.13.4.el6.x86_64
[root@localhost
二分搜索专题2-在有序二维数组中搜索一个元素
OpenMind
二维数组 算法 二分搜索
1,设二维数组p的每行每列都按照下标递增的顺序递增。
用数学语言描述如下:p满足
(1),对任意的x1,x2,y,如果x1<x2,则p(x1,y)<p(x2,y);
(2),对任意的x,y1,y2, 如果y1<y2,则p(x,y1)<p(x,y2);
2,问题:
给定满足1的数组p和一个整数k,求是否存在x0,y0使得p(x0,y0)=k?
3,算法分析:
(
java 随机数 Math与Random
SaraWon
java Math Random
今天需要在程序中产生随机数,知道有两种方法可以使用,但是使用Math和Random的区别还不是特别清楚,看到一篇文章是关于的,觉得写的还挺不错的,原文地址是
http://www.oschina.net/question/157182_45274?sort=default&p=1#answers
产生1到10之间的随机数的两种实现方式:
//Math
Math.roun
oracle创建表空间
tugn
oracle
create temporary tablespace TXSJ_TEMP
tempfile 'E:\Oracle\oradata\TXSJ_TEMP.dbf'
size 32m
autoextend on
next 32m maxsize 2048m
extent m
使用Java8实现自己的个性化搜索引擎
yangshangchuan
java superword 搜索引擎 java8 全文检索
需要对249本软件著作实现句子级别全文检索,这些著作均为PDF文件,不使用现有的框架如lucene,自己实现的方法如下:
1、从PDF文件中提取文本,这里的重点是如何最大可能地还原文本。提取之后的文本,一个句子一行保存为文本文件。
2、将所有文本文件合并为一个单一的文本文件,这样,每一个句子就有一个唯一行号。
3、对每一行文本进行分词,建立倒排表,倒排表的格式为:词=包含该词的总行数N=行号